Artigos
Cloud Computing
Por Stéphanie Antoine, Julien Dubois y Jean-Philippe Retaillé
Publicado em outubro de 2006
A Web 2.0 e seu parente técnico, o Ajax (Asynchronous JavaScript and XML), estão ganhando força graças a aplicativos como Gmail e Google Maps. Para aplicativos da Web, o maior benefício do Ajax é proporcionar uma experiência do usuário bastante aprimorada. Apesar de o JavaScript e DHTML – ou seja, as bases técnicas do Ajax – estarem à disposição há anos, a maioria dos programadores os ignorava porque era difícil aprender a usá-los. Hoje, as estruturas escritas em JavaScript, como o Dojo, podem ajudar a desenvolver aplicativos Ajax, mas ainda é necessário ter bons conhecimentos em JavaScript para isso. O Google oferece outra maneira de ajudar os desenvolvedores Java a criar aplicativos Ajax de forma mais produtiva. Essa nova estrutura, chamada Google Web Toolkit (GWT), pode ser usada de maneira eficiente com o Oracle JDeveloper. O GWT está disponível gratuitamente com o Apache License v. 2.0 em http://code.google.com/webtoolkit.
Um dos grandes problemas com o desenvolvimento em Ajax é a necessidade de dominar inúmeras tecnologias heterogêneas. Dependendo da natureza do projeto (por exemplo, aplicativos de negócios), essa pode ser uma grande desvantagem.
Além disso, diferentes browsers da Web não suportam JavaScript e DHTML da mesma maneira. Por exemplo, o Microsoft Internet Explorer e o Mozilla Firefox são compatíveis com essas tecnologias, mas com comportamentos um pouco diferentes; você precisará lidar com isso se desejar que o aplicativo seja executado tranqüilamente nos PCs dos usuários.
É verdade que a maioria das estruturas Ajax disponível hoje simplifica o trabalho de desenvolvimento, mas ainda são necessários bons conhecimentos dos recursos tecnológicos. Assim, se você pretende usar o Ajax para melhorar somente a experiência do usuário com o aplicativo –se não o estiver usando também como vantagem estratégica para os negócios – talvez seja insensato investir muito tempo e dinheiro na tecnologia.
O GWT propõe uma abordagem diferente à criação de aplicativos Ajax. Ele usa o Java como uma única linguagem de programação tanto para o cliente quanto para o servidor. Então seria isso o retorno dos applets Java? De maneira alguma: o GWT fornece um compilador que traduz o código Java no cliente em JavaScript e DTHML. Essa solução simplifica em grande medida os recursos tecnológicos do ponto de vista do programador: basta dominar apenas o Java. A desvantagem é que há menor controle sobre o código do cliente do aplicativo, porque por fim ele é gerado pelo compilador do GWT.
O código Java do cliente do aplicativo está sujeito a restrições porque o JavaScript não implementa todos os conceitos orientados a objeto e APIs disponíveis em Java. É possível usar apenas um subconjunto de palavras-chave Java e APIs (java.lang e java.util):
Além disso, o GWT fornece APIs específicos para gerenciar a GUI, a internacionalização e a análise de XML. Também fornece uma biblioteca completa para gerenciar a comunicação entre o cliente e o servidor. Usa os famosos princípios de Remote Procedure Call (RPC) implementados por um servlet genérico (RemoteServiceServlet), que pode ser especializado para suas próprias necessidades. Também é possível usar o JavaScript Object Notation (JSON) como formato de intercâmbio de dados para suas mensagens HTTP enviadas com a classe GWT HTTPRequest.
O GWT também oferece uma interface, chamada JavaScript Native Interface (JSNI), que permite combinar seu próprio código JavaScript criado manualmente com o código gerado pelo compilador do GWT. O JSNI emprega a palavra-chave native usada pelo Java Native Interface (JNI) para definir suas próprias funções JavaScript. O corpo dessas funções é definido em comentários com formatação específica.
Por fim, você pode executar o teste de unidade do código no JDeveloper com o GWTTestCase, uma especialização da classe TestCase fornecida pelo JUnit.
Foco na programação de GUI com o GWT
O Ajax muda drasticamente a maneira de desenvolver aplicativos da Web. Na maior parte do tempo, um aplicativo Ajax só precisa de uma única página da Web. O conteúdo é modificado dinamicamente pelo JavaScript e DHTML para proporcionar uma experiência do usuário semelhante àquela oferecida por aplicativos nativos.
Portanto, o GWT oferece um modelo de programação cujos princípios serão familiares aos programadores de Swing ou AWT. A GUI não é mais especificada por tags HTML como nos aplicativos da Web tradicionais. Ela é programada diretamente com código Java de maneira semelhante ao AWT ou Swing. Os bem-conhecidos conceitos da programação de GUI estão disponíveis com o GWT:
É fácil carregar a biblioteca de JavaScript do GWT e especificar o ponto de entrada do aplicativo: basta criar uma simples página HTML.
O GWT usa folhas de estilo em cascata (CSS). Cada widget tem o próprio estilo, que pode ser alterado para atender às suas necessidades. Você precisa criar o próprio CSS para substituir os padrões definidos pelo GWT.
Se os widgets padrão não atenderem às suas necessidades, você também poderá definir seu próprio widget. (Entretanto, esse assunto foge ao escopo deste artigo)
Estrutura do Projeto
Um projeto do GWT precisa estar em conformidade com uma estrutura predefinida para ser aceito pelo compilador. Assim, é obrigatório que você defina um pacote global para o aplicativo. A última parte do nome do pacote precisa ser o nome do aplicativo (como global.package.NomeDoSeuAplicativo). O arquivo XML que descreve o seu aplicativo precisa estar localizado na raiz desse pacote global. O nome desse arquivo precisa ser o nome do aplicativo seguido da extensão .gwt.xml (por exemplo, NomeDoSeuAplicativo.gwt.xml). Além disso, você precisa criar três subpacotes:
O projeto precisa declarar vários jars:
O resultado da compilação é armazenado em um único diretório cujo nome é aquele do pacote global do aplicativo. Esse diretório contém todos os elementos (como páginas HTML, CSS e arquivos JavaScript) que compreendem o lado do cliente do aplicativo. Esses elementos precisam ser implantados no aplicativo da Web, como de costume.
Modos hospedado e Web
Há dois modos de execução possíveis com o GWT. O modo hospedado executa o código do aplicativo em um servidor incorporado e um browser da Web, por isso não é preciso implantar o código em um servidor de aplicação. Ele é útil durante o teste de aplicativos porque simplifica a depuração.
O modo Web é a implantação do aplicativo da Web em Ajax em um autêntico servidor de aplicação como o OC4J. Geralmente ele é usado quando o aplicativo é executado em produção.
Criando seu primeiro aplicativo da Web em GWT com o Oracle JDeveloper
Até agora, você aprendeu como funciona o GWT; agora, vamos codificar uma amostra de aplicativo da Web ( download).
A amostra de aplicativo é um gerenciador de listas de tarefas. Seus recursos são bem simples: criar, editar, excluir e priorizar listas de tarefas. Escolhemos esse exemplo porque ele é fácil de entender, embora sua implementação abranja inúmeros recursos do GWT.
A seguir está uma captura de tela do aplicativo final:
Etapa 1: instale o GWT
Baixe o GWT no site do Google em http://code.google.com/webtoolkit/. Na época em que este artigo foi escrito, o GWT era oferecido nas versões Windows e Linux. O GWT é específico para cada plataforma porque seu modo hospedado funciona com uma versão modificada do Firefox, que por si só é dependente da plataforma. (Conseguimos usar a versão Linux do GWT em um computador Apple, mas o modo hospedado não funcionou.)
O download do GWT é feito na forma de arquivo, que precisa ser descompactado com o comando tar -xvf no Linux ou um utilitário de descompactação no Windows. Isso é tudo o que você precisa fazer para instalar o kit de ferramentas.
Etapa 2: execute o script applicationCreator
Abra uma linha de comando e vá até o diretório de instalação do GWT. Esse diretório contém o script applicationCreator, que usaremos para iniciar nosso aplicativo. Como queremos que o aplicativo seja armazenado no diretório Oracle Technology Network, acrescentamos “-out otn” como parâmetro do script. No Linux, digite:
./applicationCreator -out otn otn.todo.client.TodoApp
No Windows, use:
applicationCreator -out otn otn.todo.client.TodoApp
Esse script gera a estrutura básica do projeto, uma amostra de código “Hello world” na classe de aplicativo solicitada, além de dois scripts: TodoApp-shell, que é usado para executar o aplicativo em modo hospedado; e TodoApp-compile, que é usado para empacotar o aplicativo para ser usado em modo Web.
Etapa 3: abra o projeto no JDeveloper
Inicie o JDeveloper e crie um novo projeto da Web:
Clique no botão Next. O JDeveloper perguntará o local do novo projeto. Use o nome do aplicativo como Nome do projeto e escolha o diretório raiz do aplicativo, conforme definido na Etapa 2, como o Nome do diretório:
Clique no botão Next e valide se o aplicativo é J2EE 1.4:
Clique no botão Next e escolha as propriedades da Web do projeto: o Document Root é o diretório www do projeto atual, e J2EE Web Application Name e J2EE Context Root são o nome do projeto:
Isso criará o projeto do JDeveloper, mas ocorrerão alguns erros de compilação porque a biblioteca do GWT não está incluída no caminho de classe do projeto. Nas propriedades do projeto, selecione o nó Libraries na árvore lateral à esquerda e adicione a biblioteca gwt-user.jar:
Agora o projeto deve ser compilado e ficar assim:
Escrevendo o código do cliente
O script applicationCreator anterior criou um aplicativo básico “Hello world”, que está disponível no pacote otn.todo.client. Aqui está seu método principal:
public void onModuleLoad() {
final Button button = new Button("Click me");
final Label label = new Label();
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
if (label.getText().equals(""))
label.setText("Hello World!");
else
label.setText("");
}
});
RootPanel.get("slot1").add(button);
RootPanel.get("slot2").add(label);
}
}
Esse método cria um botão que informa “Click Me”. Ao clicar no botão, é exibido o texto “Hello World”.
Esse método é dividido em três partes:
A página HTML usada como esqueleto está localizada no diretório src/otn/todo/public. Ela define os dois elementos HTML, slot1 e slot2, como células de tabela.
Executando e depurando em modo hospedado
Agora que você criou o aplicativo e viu o resultado gerado, vamos executá-lo.
Você pode executar facilmente o projeto usando o script TodoApp-shell com a linha de comando. Esse é um método correto de iniciar o aplicativo, mas talvez você prefira iniciá-lo diretamente do JDeveloper. Para fazer isso, clique no menu Run e selecione Choose Active Run Configuration > Manage Run Configurations. Edite a configuração de execução padrão e use os comandos a seguir:
path.to.your.gwt.installation.directory/gwt-devlinux.jar!/com/google/
gwt/dev/GWTShell.class
No Windows, ficará assim:
path.to.your.gwt.installation.directory/gwt-dev-windows.jar!/com/google/ gwt/dev/GWTShell.class
-out path.to.your.gwt.installation.directory/otn/www otn.todo.TodoApp/TodoApp.htmlPara Run Directory, use:
path.to.your.gwt.installation.directory/otn
O resultado final deverá ficar assim:
Para executar o aplicativo, você precisa adicionar duas outras bibliotecas ao caminho de classe: o jar específico da plataforma do GWT e o diretório src do aplicativo:
Agora você deverá conseguir executar o aplicativo do JDeveloper.
Essa foi uma configuração um tanto complicada, mas felizmente é possível reutilizá-la para depurar o aplicativo: basta usar o botão Debug, em vez do botão Run. Você pode usar o depurador como de costume – defina pontos de interrupção, execute o código passo a passo e assim por diante:
O que é particularmente surpreendente nesse recurso é que você pode depurar o código do cliente escrito em Java com o depurador do JDeveloper padrão.
Estendendo o aplicativo da Web do GWT
Agora que você criou um aplicativo da Web simples do GWT, vamos estendê-lo usando dois dos recursos mais usados do GWT: o mecanismo RPC, que permite que o aplicativo chame o código do servidor, e o objeto History, que permite ao usuário o manuseio preciso do botão Voltar do browser.
Intercâmbio de dados entre cliente e servidor usando RPC
Até agora, você criou somente o código do cliente do nosso aplicativo: usando o compilador do GWT, você gerou vários arquivos HTML e JavaScript que serão executados no browser do usuário final. Entretanto, esse aplicativo não será de muita utilidade se não conseguir se comunicar com o servidor.
Com o GWT, a comunicação cliente/servidor é uma questão de codificar um servlet e fazê-lo se comunicar com o aplicativo. Veja o que você tem de fazer.
Crie uma interface que defina o seu serviço. Essa interface precisa estender a interface com.google.gwt.user.client.rpc.RemoteService do Google e estar localizada no pacote do cliente (otn.todo.client, em nosso exemplo).
Depois, codifique uma interface que permita ler e escrever uma lista de tarefas no servidor:
package otn.todo.client;
import java.util.List;
import com.google.gwt.user.client.rpc.RemoteService;
public interface TodoListBackupService extends RemoteService {
/**
* Save the to-do list on the server.
*/
void saveTodoList(List todoList);
/**
* Get the to-do list on the server.
*/
List getTodoList();
}
Codifique o servlet. No servidor, você precisa codificar uma classe que:
package otn.todo.server;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import otn.todo.client.Todo;
import otn.todo.client.TodoListBackupService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class TodoListBackupServiceImpl extends RemoteServiceServlet implements
TodoListBackupService {
private static final String TODOLIST_KEY = "TODOLIST_KEY";
public void saveTodoList(List todoList) {
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
session.setAttribute(TODOLIST_KEY, todoList);
}
public List getTodoList() {
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
if (session.getAttribute(TODOLIST_KEY) == null) {
List todoList = new ArrayList();
Todo todo = new Todo("Hello from the server");
todoList.add(todo);
return todoList;
} else {
return (List) session.getAttribute(TODOLIST_KEY);
}
}
}
Esse servlet armazena somente a lista de tarefas no HttpSession do usuário; essa é, evidentemente, uma maneira básica de salvar dados. Em um aplicativo normal, você poderia usar JNDI para acessar EJBs, ou qualquer um dos padrões tradicionais usados para acessar um serviço de negócios a partir de um servlet.
Por fim, é necessário configurar esse servlet no container do servlet. Se estiver usando o shell do GWT, você poderá configurá-lo no arquivo de configuração *.gwt.xml, que é TodoApp.gwt.xml em nosso exemplo:
<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Specify the app entry point class. -->
<entry-point class='otn.todo.client.TodoApp'/>
<servlet path="/todoListBackupService"
class="otn.todo.server.TodoListBackupServiceImpl"/>
</module>
Se quiser configurá-lo em outro servidor de aplicação, como o OC4J, bastará adicionar a configuração XML normal ao arquivo WEB-INF/web.xml:
<servlet>
<servlet-name>TodoListBackupService</servlet-name>
<servlet-class>otn.todo.server.TodoListBackupServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TodoListBackupService</servlet-name>
<url-pattern>/todoListBackupService</url-pattern>
</servlet-mapping>
Adicione um componente de ligação. O componente de ligação necessário é a classe Async, que precisa seguir estas regras:
package otn.todo.client; import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface TodoListBackupServiceAsync {
/**
* Save the to-do list on the server.
*/
void saveTodoList(List todoList, AsyncCallback callback);
/**
* Get the to-do list on the server.
*/
void getTodoList(AsyncCallback callback);
}
Use-o no aplicativo. Para acessar o código do servidor a partir do aplicativo cliente, use a classe com.google.gwt.core.client.GWT, que pode criar um objeto muito especial:
TodoListBackupServiceAsync todoListBackupService = (TodoListBackupServiceAsync) GWT.create(TodoListBackupService.class);
Isso cria em tempo de execução uma classe que implementa duas interfaces:
A segunda interface é usada para configurar a classe para que possa apontar para o servlet definido na Etapa 2:
ServiceDefTarget endpoint = (ServiceDefTarget) todoListBackupService;
endpoint.setServiceEntryPoint("/todoListBackupService");
Agora que você configurou esse objeto para acessar o serviço do servidor, vamos acessar o serviço. Conforme visto na Etapa 3, a interface Async permite acessar todos os métodos definidos no serviço, com o acréscimo do parâmetro de callback AsyncCallback. Esse parâmetro é usado para definir o comportamento do aplicativo, dependendo do sucesso ou falha da chamada do servidor:
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
printTodoList();
}
public void onFailure(Throwable caught) {
Window.alert("Warning :the to-do list could not be saved on the server.
Maybe the server is down.");
}
};
Vamos reunir tudo. A seguir está o código completo dos dois métodos do cliente que acessam o serviço de negócios TodoListBackupService: um para salvar a lista de tarefas no servidor, e outro para lê-la:
/**
* Update the to-do list with data from the server.
*/
private void updateTodoListFromServer() {
TodoListBackupServiceAsync todoListBackupService =
(TodoListBackupServiceAsync)GWT.create(TodoListBackupService.class);
ServiceDefTarget endpoint = (ServiceDefTarget)todoListBackupService;
endpoint.setServiceEntryPoint("/todoListBackupService");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
todoList = (List)result;
saveTodoListInHistory();
}
public void onFailure(Throwable caught) {
Todo todo =
new Todo("ERROR!! Server could not be reached.");
todoList.add(todo);
saveTodoListInHistory();
}
};
todoListBackupService.getTodoList(callback);
}
/**
* Save the to-do list on the server.
*/
private void saveTodoListOnServer() {
saveTodoListInHistory();
TodoListBackupServiceAsync todoListBackupService =
(TodoListBackupServiceAsync)GWT.create(TodoListBackupService.class);
ServiceDefTarget endpoint = (ServiceDefTarget)todoListBackupService;
endpoint.setServiceEntryPoint("/todoListBackupService");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
printTodoList();
}
public void onFailure(Throwable caught) {
Window.alert("Warning : the to-do list could not be saved on the server.
Maybe the server is down.");
}
};
todoListBackupService.saveTodoList(todoList, callback);
}
O aplicativo de exemplo faz uma chamada do servidor na inicialização. Essa chamada retorna a lista de tarefas mais recente salva no HttpSession do usuário ou uma nova lista de tarefas que contém a tarefa “Hello from the server”:
Gerenciando o botão Voltar
Em aplicativos da Web sofisticados, o botão Voltar do browser muitas vezes fica desativado. Aplicativos Ajax tradicionais não suportam o comportamento da Web padrão de retornar para a página anterior.
O GWT, em contrapartida, permite a manipulação programática do botão Voltar. Esse é um recurso poderoso, porém caprichoso, que exploraremos com o nosso exemplo de aplicativo. A idéia é usar o botão Voltar como um botão Desfazer: se você clicar nele, será exibida a lista de tarefas conforme ela estava antes do evento mais recente. Da mesma maneira, o botão Avançar funcionará como um botão Refazer.
Implemente a interface HistoryListener. Para gerenciar o botão Voltar via programação, o aplicativo do GWT precisa implementar a interface com.google.gwt.user.client.HistoryListener. Isso obriga a escrever o método onHistoryChanged(String _historyToken):
public class TodoApp implements EntryPoint, HistoryListener {
/**
* This method is called whenever the application's history changes.
*/
public void onHistoryChanged(String _historyToken) {
if (Integer.parseInt(_historyToken) + 1 != historyToken) {
if (historyMap.get(_historyToken) != null) {
historyToken = Integer.parseInt(_historyToken);
todoList = (List) historyMap.get(_historyToken);
}
}
printTodoList();
}
Esse método é destinado a receber eventos quando o histórico do browser é alterado. É necessário adicioná-lo como listener ao objeto History do GWT. Normalmente isso é feito no método onModuleLoad(), por isso o objeto History é executado corretamente na inicialização:
/**
* This is the entry point method.
*/
public void onModuleLoad() {
History.addHistoryListener(this);
}
Agora, o método onHistoryChanged(String _historyToken) é chamado sempre que o histórico do browser é alterado.
Esse método é capaz de recriar o estado do aplicativo de acordo com um token transmitido como parâmetro. Em nosso exemplo, você usará esse token como uma chave para localizar uma lista de tarefas armazenada em um mapa de histórico.
Adicione itens ao histórico. Para que o método onHistoryChanged(String _historyToken) funcione, você precisa ter os itens armazenados no histórico com antecedência.
É fácil fazer isso com o objeto History, usando o método newItem(String historyToken) estático:
private void saveTodoListInHistory() {
List todoListClone = new ArrayList();
Iterator it = todoList.iterator();
while (it.hasNext()) {
Todo todo = (Todo) it.next();
todoListClone.add(todo.clone());
}
historyMap.put(String.valueOf(historyToken), todoListClone);
History.newItem(String.valueOf(historyToken));
historyToken++;
}
Em nosso exemplo, você armazenou o estado do aplicativo em um mapa para que ele possa ser localizado usando o token de histórico. Observe que você usou um número como token de histórico, mas que qualquer seqüência de caracteres pode ser usada no lugar.
Implantando o aplicativo da Web
Para implantar um aplicativo da Web criado com o GWT, compile o código do cliente, empacote o resultado interno do arquivo .war do aplicativo da Web e implante o arquivo .war no seu servidor de aplicação preferido, o OC4J.
Compilando o código do cliente
Há várias maneiras de compilar seu código do cliente. Quando você usa o script applicationCreator, o GWT cria um script de shell chamado TodoApp-compile. Você pode iniciá-lo com a linha de comando. Como o TodoApp-shell, é uma ótima maneira de compilar o aplicativo; entretanto, talvez você queira iniciá-lo diretamente do JDeveloper.
Outra maneira de compilar o código é executar o aplicativo em modo hospedado para que possa ser executado diretamente do JDeveloper. A barra de ferramentas da janela do aplicativo contém um botão de compilação/procura, como este:
Ao final do processo de compilação, o browser da Web padrão será aberto para você poder testar o resultado. A janela do shell de desenvolvimento do GWT será exibida se a compilação for bem-sucedida:
Independentemente de como o código é compilado, você encontrará os arquivos gerados no www/otn.todo.TodoApp de seu projeto.
A última maneira de compilar o código é usar Ant. O GWT não oferece uma tarefa Ant específica, mas é possível iniciar qualquer classe Java (como GWTCompiler) com a tarefa Ant Java padrão. Primeiro, defina o caminho para incluir os jars do GWT:
<path id="project.class.path">
<pathelement path="${java.class.path}/"/>
<pathelement location="src"/>
<pathelement path="/your/path/to/gwt-user.jar"/>
<pathelement path="/your/path/to/gwt-dev-linux.jar"/>
<!-- ... -->
</path>
Agora, defina uma tarefa dedicada à compilação do seu código do cliente:
Defina as variáveis gwt.output.dir e entry.point.class em um arquivo de propriedades, como este:
gwt.output.dir=www
entry.point.class=otn.todo.TodoApp
Por fim, declare o arquivo de propriedades (neste caso, build.properties) no script Ant, assim:
<property file="build.properties"/>
Você pode iniciar diretamente esse novo destino selecionando Run Target GWTCompile no menu Context da tarefa:
A janela de Apache Ant Log mostrará o resultado a seguir:
GWTcompile: [java] Output will be written into www\otn.todo.TodoApp [java] Compilation succeeded BUILD SUCCESSFUL
Implantação no OC4J
Após compilar o aplicativo, implantá-lo em OC4J é apenas uma questão de criar um perfil de implantação correto. Se você seguiu as etapas descritas anteriormente, você já deve ter um perfil de implantação padrão. Caso contrário, basta selecionar File > New... > Deployment Profiles > WAR File e criar um novo perfil.
Usando sua configuração, tudo deve funcionar imediatamente. Entretanto, se encontrar algum problema, confira os seguintes erros comuns:
O aplicativo implantado tem duas partes:
Em termos de performance, servir recursos estáticos é muito eficiente; o principal gargalo de performance do nosso aplicativo deve vir da comunicação cliente/servidor. Mas graças ao OC4J, temos acesso a alguns gráficos interessantes de performance do servidor:
Conforme mostra esse gráfico, em carga normal (algumas solicitações por segundo) a parte do servidor do aplicativo responde em menos de 4 ms em média – um resultado excelente.
Stéphanie Antoine é desenvolvedora de J2EE sênior e trabalha em uma grande empresa francesa de consultoria em software. Julien Dubois e Jean-Philippe Retaillé são especialistas em J2EE e autores de vários livros; seu livro mais recente, Spring par la Pratique (Eyrolles, 2006) é o primeiro em francês sobre a estrutura do Spring J2EE.