Gastaldi's Blog

Mais um blog sobre Java …

Arquivos Mensais: novembro 2010

Filtro para sessão expirada

Se você programa em Java EE para aplicações Web, já deve ter conhecimento do objeto HttpSession e a sua expiração por inatividade. Neste post apresento um exemplo de um filtro que permite detectar no momento da requisição se a sessão expirou e assim evitar erros como Session already invalidated e afins:

package com.george.utils;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Filtro para controle de expiração da sessão.
 * 
 * Caso a sessão seja expirada, redireciona para uma URL definida
 * 
 * @author George Gastaldi
 * 
 */
public class SessionExpiredFilter implements Filter {

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	/**
	 * Verifica se a sessão não expirou, caso contrário joga erro 408 (REQUEST TIMEOUT).
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		// Verifica se existe uma sessão para comparar e se a session ID
		// retornada pelo cliente é a mesma
		boolean sessionInvalidated = isSessionInvalidated(httpRequest);
		if (sessionInvalidated) {
			httpResponse.addCookie(createCookie(httpRequest));
			httpResponse.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT);
		} else {
			chain.doFilter(request, response);
		}
	}
	
	/**
	 * Retorna se a sessão foi invalidada
	 * @param httpRequest
	 * @return
	 */
	boolean isSessionInvalidated(HttpServletRequest httpRequest) {
		String requestedSessionId = httpRequest.getRequestedSessionId();
		HttpSession session = httpRequest.getSession(false);	
		if (session == null) {
			return (requestedSessionId != null);
		} else {
			return (requestedSessionId != null && !session.getId().equals(requestedSessionId));
		}
	}
	
	/**
	 * Mata o cookie de sessão do browser
	 * @param request
	 * @return
	 */
	private Cookie createCookie(HttpServletRequest request) {
		Cookie cookie = new Cookie("JSESSIONID", request.getRequestedSessionId());
		cookie.setMaxAge(0); // Matar o cookie
		String contextPath = request.getContextPath();
		if (!"".equals(contextPath)) {
			cookie.setPath(contextPath);
		} else {
			cookie.setPath("/");
		}
		return cookie;
	}


	/**
	 * @see Filter#destroy() 
	 */
	public void destroy() {
	}

}

Você pode configurar no seu web.xml o filtro da seguinte maneira:

<filter>
	<filter-name>Session Expired Filter</filter-name>
	<description>Filtro para sessões expiradas. Lança erro 408 se a sessão expirou</description>
	<filter-class>com.george.utils.SessionExpiredFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>Session Expired Filter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

Anúncios

Criando uma solução para atualização de aplicações remotas

Imagine o seguinte: Você desenvolve uma aplicação (web ou não) e ela roda em um ambiente remoto (o ambiente de produção do seu cliente, seja em um servidor de aplicação JBoss ou Tomcat instalado no ambiente remoto) e você precisa garantir que a cada nova release da sua aplicação, o cliente tenha sempre a última versão. Neste post pretendo mostrar como você pode fazê-lo utilizando o Apache Maven e o Apache Ant para gerenciamento das versões do seu projeto e automatização de tarefas.

Não pretendo demonstrar uma solução completa, mas apresentar uma prova de conceito que pode ser melhorado. Para quem não conhece o Maven ou o Ant, sugiro ler as respectivas documentações. Para que funcione, você já deve ter um repositório remoto Maven configurado (sugiro o Sonatype Nexus) e (obviamente) a sua aplicação já deve estar “mavenizada”.

Você pode instalar o Apache Ant na sua maquina que vai rodar o script e adicionar o JAR do Maven Tasks for Ant no lib ou então seguir os passos abaixo para criar uma distribuição do Ant já com as bibliotecas necessárias. Se você não gosta de Maven, então sugiro passar pro passo 3 (onde está o início do script)

1) Queremos que esta solução seja instalável pelo cliente, logo deve ser ao menos distribuída em um arquivo ZIP que pode ser descompactado. Começamos a criar um projeto Maven e logo teremos o seguinte pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.george.app</groupId>
	<artifactId>george-atualizador</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>George :: Atualizador</name>
	<packaging>pom</packaging>
	<dependencies>
		<dependency>
			<groupId>org.apache.ant</groupId>
			<artifactId>ant</artifactId>
			<version>1.8.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-ant-tasks</artifactId>
			<version>2.1.1</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-assembly-plugin</artifactId>
				<version>2.2</version>
				<executions>
					<execution>
						<id>gera-zip</id>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
						<inherited>false</inherited>
						<configuration>
							<descriptors>
								<descriptor>src/main/assembly/instalador.xml</descriptor>
							</descriptors>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Este pom.xml é a base do nosso projeto. Ele tem como dependência o Apache Ant e uma extensão que permite invocar tarefas do Maven dentro de um script Ant.

2) Note que é usado também um plugin (assembly) para montagem do ZIP. Ele tem a seguinte estrutura:

<assembly
	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
	<id>instalador</id>
	<formats>
		<format>zip</format>
	</formats>
	<fileSets>
		<fileSet>
			<directory>src/main/assembly/bin</directory>
			<outputDirectory>bin</outputDirectory>
		</fileSet>
		<fileSet>
			<directory>src/main/assembly/conf</directory>
			<outputDirectory>conf</outputDirectory>
		</fileSet>
		<fileSet>
			<directory>src/main/assembly</directory>
			<includes>
				<include>build.xml</include>
			</includes>
			<outputDirectory>/</outputDirectory>
		</fileSet>
	</fileSets>
	<dependencySets>
		<dependencySet>
			<outputDirectory>lib</outputDirectory>
			<useProjectArtifact>false</useProjectArtifact>
			<outputFileNameMapping>${artifact.artifactId}.${artifact.extension}
			</outputFileNameMapping>
		</dependencySet>
	</dependencySets>
</assembly>

3) Agora você só precisa do arquivo build.xml (o mais importante – que vai conter as ações de atualização da aplicação) e os executáveis (Arquivos BAT) do Apache Ant (para invocá-lo quando necessário).


<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="default" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
	<!-- ================================= 
          target: default              
         ================================= -->
	<target name="default" depends="resolver-dependencias" description="description">
		<copy todir="temp">
			<fileset refid="dependency.fileset" />
			<mapper classname="org.apache.maven.artifact.ant.VersionMapper" from="${dependency.versions}" to="flatten" />
		</copy>
	</target>

	<target name="resolver-dependencias">
		<artifact:dependencies filesetId="dependency.fileset" versionsId="dependency.versions" settingsFile="conf/settings.xml">
			<dependency groupId="com.george.app" artifactId="minha-app-maven" version="[1.0.0,2.0.0)" />
		</artifact:dependencies>
	</target>
</project>

Este script vai conectar no seu repositório remoto (está especificado no seu arquivo conf/settings.xml – veja como criar um aqui), baixar a última versão disponível que esteja entre a versão 1.0.0 e menor que a 2.0.0 (mais informações sobre o versionamento maven aqui) e gravar em uma pasta temp sem a informação de versão (que é o padrão do Maven).

A partir daí, você pode incrementar o seu script para copiar o WAR para o seu Tomcat ou JBoss e até mesmo agendá-lo (usando cron ou o agendador do windows mesmo, ou porque não o Hudson) para executá-lo toda noite, enfim, as possibilidades são muitas.

Enfim, este post teve a intenção de mostrar que o Apache Maven não é só mais uma ferramenta de builld, mas que usado em conjunto com o Apache Ant, chega a agradar gregos e troianos ! 🙂