sexta-feira, 4 de dezembro de 2009

Apache Proxy

Geralmente, todo servidor de aplicação vem com um servidor HTTP embutido.
Por exemplo, se vc subir um Tomcat, na porta 8080, ele por si só vai responder HTTP.

O que acontece é que o Apache é mais rápido para servir conteúdo (cache, etc) portanto, muitos utilizam colocar o Apache na frente dos servidores HTTP dos aplications servers, servindo conteúdo estático (html, js, css, etc) diretamente, e somente redirecionando para o app server quando necessario.

Nesse caso, o Apache atua como um proxy, interceptando todas as conexões TCP na porta que estiver ouvindo, e encaminhando para a porta TCP do application server:

CLIENT ---- ---- APACHE ----- ----- APP SERVER

Segue um exemplo abaixo, à ser aplicado dentro de um do Apache, redirecionando todas as URLs para um aplication server rodando na propria maquina, na porta 8080:

RewriteEngine on
RewriteLogLevel 1
RewriteLog /logs/rewrite.log
RewriteRule /(.*)$ http://127.0.0.1:8080/$1 [P,L]
ProxyRequests Off
ProxyVia Block
ProxyPreserveHost On
ProxyTimeout 10

quinta-feira, 13 de agosto de 2009

Represando execução de métodos Java através de Reflection

A Reflection API é um poderoso recurso da JVM que torna possível invocação de métodos de objetos em memória através de forma programática.
Quando bem utilizado, esse recurso pode executar tarefas extremamente arrojadas.


Requisito:

Represar todos os métodos DAOs em uma sessão web, e executá-los todos de uma vez dentro de uma transação ao final da sessão
JVM 5 + Spring + Jetty 1.6


Solução:

Interceptando todas as chamadas dos métodos DAOs, armazeno uma sequência de invocações em uma Collection em um Statefull Session Bean, de forma que fiquem represados em memória.

StatefullBeanInterface:


addCallStack(Object target, String methodName, Object... args);



ExampleDAO:


@Transactional(propagation = Propagation.MANDATORY)
addUser(User user) {
// real persistence operation
}

addUser(StatefullBean s, User user) {
// interceptor operation
s.addCallStack(this, "addUser", user);
}


Ao final da sessão, o usuário confirma a execução dos métodos. Agora entra em ação a Reflection.


@Transactional(propagation = Propagation.REQUIRES_NEW)
public void execCallStack() throws CallStackException {

for (Object o : callStack.keySet()) {

List<MethodCall> call = callStack.get(o);

for (MethodCall method : call) {

Object[] args = method.getArgs();
Method[] allMethods = o.getClass().getDeclaredMethods();

for (Method m : allMethods) {

if (m.getName().equals(method.getMethodName()) && m.getGenericParameterTypes().length == args.length) {
try {
m.invoke(o, args);
break;
} catch (Exception e) {
throw new CallStackException(e);
}
}
}
}
}
}


Passo a passo:


@Transactional(propagation = Propagation.REQUIRES_NEW)
public void execCallStack()throws CallStackException {


Solicitamos ao container que crie uma nova transação ao iniciar a execução dos métodos DAO represados.
Os métodos são anotados com propagação de transação mandatória (Propagation.MANDATORY). Dessa forma, se forem invocados foram de uma transação, uma exceção será gerada.


for (Object o : callStack.keySet()) {
List<MethodCall> call = callStack.get(o);
for (MethodCall method : call) {
Object[] args = method.getArgs();


Estamos percorrendo a Collection com os objetos alvo da invocação, o nome dos métodos e seus respectivos argumentos.



Method[] allMethods = o.getClass().getDeclaredMethods();
for (Method m : allMethods) {


Aqui começa a reflection. getDeclaredMethods retorna todos os métodos de uma classe. A classe Method encapsula suas declarações, como argumentos, exceções, encapsulamento, entre outros.



if (m.getName().equals(method.getMethodName()) && m.getGenericParameterTypes().length == args.length) {


Procuramos o método correspondente através do nome e a quantidade de argumentos, para minimizar eventuais problemas com sobrecarga.
Checagens adicionais podem ser feitas, porém no caso acima não houve necessidade.


m.invoke(o, args);


Finalmente o método invoke executa o código. O primeiro argumento é uma instância Object que implemente a Classe alvo, e o segundo argumento é um vetor com os métodos.
A CallStackException é uma exceção Runtime criada especificamente para essa situação, para efetuar o rollback das operações em banco em caso de algum método falhar.

Mais informações:

http://java.sun.com/docs/books/tutorial/reflect/
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

sexta-feira, 13 de março de 2009

GOMS - Metrificação de usabilidade

Para se medir qualquer coisa, é necessário uma métrica adequada.
Para metrificação de usabilidade, gostaria de apresentar padrão GOMS, e gostei muito dos resultados, principalmente no quesito "mostrar ao cliente".
Na prática, funciona assim:

1) Estabelecer custos para determinadas ações de usabilidade:

Mover o ponteiro do mouse até determinado ponto = 1
Clicar e arrastar um item = 4
Localizar um botão = 2
Tomar uma decisão booleana = 3
Preencher um form aprox 10 campos = 10
...

2) Listar os casos de uso seu sistema

Cadastrar um usuário
Preencher uma nota fiscal
Alterar dados de um usuário
...

3) Para cada caso de uso, pontue o custo de acordo com a primeira tabela

Dessa forma, você terá como identificar e aprimorar a usabilidade de seu sistema, utilizando uma metrificação numérica.

terça-feira, 3 de março de 2009

Criptografia de cookies

Criptografia de cookies é um requisito de segurança quando se armazenam informações críticas nos navegadores dos clientes de seu portal.
Em Java, os algorítimos de criptografia populares (AES, DES3) trabalham com vetores de bytes, o que demanda certa atenção no momento de convertê-los para uma String para se salvar em um cookie, em relação à codificação de caracteres (UNICODE UTF-8 e URLEncode).
Pode-se utilizar Base64 para converter a informação binária para String, porém é possível encarar problemas de padding de bytes.
A melhor solução encontrada foi a codificação dos bytes em Hexadecimal. Fica um pouco maior que o Base64, porém, totalmente bugfree, pois o output só terá caracteres "naturais", de 0 a 9 e A a F. Nada de / = + e outros caras estranhos pra quebrar a codificação de sua string. O pacote Apache Commons Codec implementa ambas as conversões.

http://java.sun.com/javase/technologies/security/
http://pt.wikipedia.org/wiki/Base64
http://commons.apache.org/codec/