Foi liberada a versão inicial (early draft) da especificação Servlet 3.1 (JSR 340). Entre as melhorias estão o suporte ao desenvolvimento de aplicações em nuvem PaaS; aperfeiçoamentos em segurança e no gerenciamento de sessões e recursos; IO assíncrono baseado no NIO2, e simplificação da criação de servlets assíncronos. O Servlet 3.1, além disso, faz uso dos utilitários de concorrência do Java EE (JSR 236) e introduz suporte a WebSockets.
Suporte a ambientes em nuvem
O Servlet 3.1 atende ao objetivo principal do futuro Java EE 7: a execução de aplicações em ambientes de nuvem públicos e privados, seguindo o modelo de Plataforma como Serviço (PaaS).
Dentro de um container web, será possível compartilhar uma aplicação com múltiplos clientes, ou ter uma instância de aplicação instalada por cliente. Pode-se fazer o mapeamento dos clientes diretamente no container e garantir o isolamento das aplicações instaladas. Além disso, recursos de configuração personalizados poderão ser criados para cada cliente, além de se poder definir metadados para os serviços.
Para suportar PaaS efetivamente, são levados em consideração requisitos como segurança, estados das sessões, gerenciamento de recursos (ex.: conexões com bancos de dados, filas de mensagens e outros), além do isolamento das aplicações.
Servlets assíncronos
Com o processamento assíncrono de servlets, será possível fazer uma requisição para um servlet iniciar alguma tarefa em paralelo, enquanto é gerada a resposta para quem iniciou a solicitação.
Quando um processo assíncrono for iniciado através da chamada ao método request.startAsync() ou request.startAsync(request, response), uma nova thread ou método de retorno será responsável por gerar a resposta e por chamar o método complete(). Como alternativa, pode-se fazer uma requisição usando o método dispatch() da classe AsyncContext. Veja um exemplo:
@WebServlet(name = "Pedido", urlPatterns = {"/Pedido"}, asyncSupported = true) public class Pedido extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Inicia um contexto assíncrono. AsyncContext ac = request.startAsync(request, response); ac.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { System.out.println("onComplete"); } @Override public void onTimeout(AsyncEvent event) throws IOException { System.out.println("onTimeout"); } @Override public void onError(AsyncEvent event) throws IOException { System.out.println("onError"); } @Override public void onStartAsync(AsyncEvent event) throws IOException { System.out.println("onStartAsync"); } }); ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10); executor.execute(new ProcessamentoAssincrono(ac)); } } class ProcessamentoAssincrono implements Runnable { private AsyncContext ac; public ProcessamentoAssincrono(AsyncContext ac) { this.ac = ac; } @Override public void run() { //Executa o processamento assíncrono. //Quando terminar, avisa o contexto assíncrono que completou a tarefa. ac.complete(); } }
A especificação da classe AsyncContext deixa claro que ocorrerá uma IllegalStateException se os métodos getRequest() ou getResponse() forem chamados após a solicitação dos métodos complete() e dispatch().
IO assíncrono
Para auxiliar o IO (Entrada e Saída) assíncrono, foi adicionada a funcionalidade de IO sem bloqueio, que será usada pelos containers web para melhorar a escalabilidade. Esse tipo de IO permite aumentar o número de conexões que podem ser tratadas simultaneamente, além de trazer outras vantagens. Para isso, foram criadas novas interfaces, como ReadListener e WriteListener, que irão fornecer métodos para ler e escrever dados sem bloqueio.
Houve ainda alterações na classe ServletInputStream, para receber o ReadListener e informar quando os dados podem ser lidos sem bloqueio; a classe informa ainda se a leitura dos dados associados a um ServletReader ou ServletInputStream já terminou. E a classe ServletOutputStream foi alterada, para que possa receber um WriteListener, que será notificado quando o servlet puder gravar os dados, sem que haja o bloqueio.
Melhorias de segurança
Quando for especificado o uso de run-as (anotação @RunAs), os métodos init() e destroy() do Servlet também devem propagar esta regra de segurança quando um EJB for chamado. Por exemplo:
@RunAs("Admin") @WebServlet(name="CalculatorServlet", urlPatterns={"/CalculatorServlet"}) public class CalculatorServlet extends HttpServlet { @EJB private ShoppingCart myCart; @Override public void destroy() { super.destroy(); myCart.destroy(); } @Override public void init() throws ServletException { super.init(); myCart.init(); } }
Suporte a WebSockets
No Servlet 3.1 foi incluído o suporte necessário para utilização dos WebSockets e o uso de outros protocolos baseados no HTTP. Foi adicionado suporte ao cabeçalho Upgrade do HTTP/1.1, em que o cliente especifica o protocolo de comunicação que deseja usar com o servidor. Isso facilita o uso de diferentes protocolos nos WebSockets.
Para contemplar tal funcionalidade, foi adicionado o método upgrade(ProtocolHandler handler) na interface HttpServletRequest. O container não precisa conhecer o protocolo de comunicação, devendo apenas passar um WebConnection para o método ProtocolHandler.init() encapsular o protocolo.
Outras melhorias
Entre outras pequenas melhorias, a interface ServletRequest possui agora os métodos getContentLengthLong(), que obtém o tamanho em bytes do corpo da requisição, e o setContentLengthLong(long len) que define o tamanho do conteúdo do corpo da resposta da requisição.
Mais informações sobre a especificação Servlet 3.1 podem ser obtidas na página da JSR 340, na lista de discussão ou no site do projeto. Caso haja interesse em contribuir com a especificação, pode-se enviar um email para users@servlet-spec.java.net, com sugestões e críticas.