Proxy/Interceptor à la carte com Groovy

Groovy é uma linguagem de script fantástica, tem um poder e facilidade assombrosa. Muitas dessas facilidades não existem quando trabalhamos com Java. Algumas existem mas não são para meros mortais e em muitas vezes temos que envolver diversos outros frameworks para executar o que queremos.

O Groovy possui diversas maneiras de se trabalhar com proxy/interceptors e vou mostrar algumas dessas maneiras nesse post. Considere então a seguinte interface Java.

package com.blogspot.diegopacheco.groovy.proxy;

/**
* Interface que representa o contrato de OrdemCompra
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/
public interface OrdemCompra {
public void comprar();
}

Vamos aplicar o proxy Groovy em cima de uma interface Java, a interface OrdemCompra. Você poderia aplicar esse proxy em uma interface Groovy também. Vou mostrar a primeira fora de proxy com o proxy-o-mate que é um dos módulos do Groovy.



package com.blogspot.diegopacheco.groovy.proxy

import static org.kordamp.groovy.util.ProxyOMatic.proxy

/**
* Proxy implementado em Groovy sobre uma interface Java.
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/
public class GroovyProxy{   

public static void main(String []args){

def p = proxy( OrdemCompra ) {              
comprar { -> println 'Compra efetuada com sucesso no Groovy!!!' }
}              
p.comprar()               

}       
}

Ao rodar esse código você vai ter uma saida assim
Compra efetuada com sucesso no Groovy!!!

O Código é tão simples que eu até não precisava explicar. Mas utilizamos uma categorie do Groovy informando qual é a interface que terá o proxy. Depois informamos os métodos e passamos um Closure como implementação.

Mas não é só isso, existem outras formas. Vamos ver um interceptor com mais poder agora, e também um pouco mais complexo! Considere a seguinte classe groovy a baixo.

package com.blogspot.diegopacheco.groovy.interceptor

/**
* Classe Groovy ordinária.
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/
public class DumieClass {
public void fazAlgo(){
println 'ola mundo...'
}
}

Como podem ver é uma classe muito simples e com apenas um método chamado de fazAlgo(). Agora vamos ao código do interceptor do Groovy. Esse interceptor implementa a interface groovy.lang.Interceptor. Você não necessita fazer o import dele pois está no pacote lang do Groovy e o import para esse pacote accontece automáticamente.

Vamos ao código do interceptor então.
package com.blogspot.diegopacheco.groovy.interceptor

import org.codehaus.groovy.runtime.*

/**
* Interceptor de métodos do Groovy.
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/
public class GroovyInterceptor implements Interceptor{

Object beforeInvoke(Object object, String methodName, Object[] arguments){
println " BEFORE $object.$methodName($arguments)"
null
}

boolean doInvoke(){ true }

Object afterInvoke(Object object, String methodName, Object[] arguments,Object result){
println " AFTER $object.$methodName($arguments): $result"
result
}

}

Esse interceptor tem 3 métodos basicamente; Sendo que os métodos e suas responsabilidades são:
  • boolean doInvoke(): retorna true or false e esse metodo decide se a execução irá ocorrer ou não. Por padrão estou retornando true.
  • Object beforeInvoke(Object object, String methodName, Object[] arguments): Que é chamado antes da execução de um método e você recebe como parâmetros todo o contexto da execução do método, ou sejá, parâmetros, nome do metodo e objeto.
  • Object afterInvoke(Object object, String methodName, Object[] arguments,Object result): Que é executado depois da execução do metodo além dos parametros do contexto do método existe o retorno do método que está na variavel result assim você pode modificar o retorno do método original.
Vamos ao código de uso então. Que é mais uma classe Groovy.
package com.blogspot.diegopacheco.groovy.interceptor

import org.codehaus.groovy.runtime.*

/**
* Classe de testes com o Interceptor padrão do Groovy.
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/
public class GroovyInterceptorTest{

public static void main(String []args){       

def proxy = ProxyMetaClass.getInstance( DumieClass )
proxy.interceptor = new GroovyInterceptor()       

proxy.use{
new DumieClass().fazAlgo()
}   
}

}

Aqui criamos a intancia de um proxy usando a ProxyMetaClass e depois através de uma categorie do Groovy invocamos o metodo proxyado que o interceptor que criamos irá pegar. O resultado da execução seria algo assim.

BEFORE class com.blogspot.diegopacheco.groovy.interceptor.DumieClass.ctor({})
AFTER class com.blogspot.diegopacheco.groovy.interceptor.DumieClass.ctor({}): com.blogspot.diegopacheco.groovy.interceptor.DumieClass@1ac1fe4
BEFORE com.blogspot.diegopacheco.groovy.interceptor.DumieClass@1ac1fe4.fazAlgo({})
ola mundo...
AFTER com.blogspot.diegopacheco.groovy.interceptor.DumieClass@1ac1fe4.fazAlgo({}): null

Como você pode ver o Groovy tem diversas formas de implementar esse tipo de código. Mas ainda não acabou vamos a mais uma forma de proxy só que com a MetaClass agora. A MetaClass é o cerne do Groovy graças a esse recurso que ele adiciona metodos a classes final como a String por exemplo.

Então olhe esse código
package com.blogspot.diegopacheco.groovy.interceptor

/**
* Testes com a metaClass do Groovy
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/

class Stuff {
def invokeMe() { "foo" }
}

Stuff.metaClass.invokeMethod = { String name, args ->   
def metaMethod = Stuff.metaClass.getMetaMethod(name, args)  
def result = metaMethod.invoke(delegate,args)
println 'interceptado...'
return result
}

println new Stuff().invokeMe()

Aqui estamos adicionado um metodo em tempo de runtime a classe Stuff. Através da metaClass do Groovy. Nesse código estou executando o método original mas coloquei um print para provar que foi interceptado de facto. Assim você poderia fazer o que quizer. A execução desse código seria assim.

interceptado...
foo

E por fim para finalizar com chave de ouro, o Groovy permite que através de um Closure um método sejá adicionado a metaClasss. Esse é um procedimento muito simples mas ao mesmo tempo poderoso.

package com.blogspot.diegopacheco.groovy.interceptor

/**
* Exemplo de uso de metaClass. 
*
* @author Diego Pacheco
* @since 17/02/2009
* @version 1.0 
*
*/

// metaClass
DumieClass.metaClass.aumenta << { it -> it.toUpperCase() }       
def b = new DumieClass()
println b.aumenta("teste groovy")

Como podem ver utilizei a DumieClass e criei um Closure e adicione ele como metodo da classe DumieClass. A baixo a classe Dumie é instanciada e como podem perceber estou utilizando o novo mnetodo que eu acabei de adicionar agora. Na verdade nesse caso não seria bem um proxy, mas um tipo de decoretor, mas igual dá um bom efeito.

Bomo como puderam ver o Groovy se mostra muito versátil e fácil para implementação de proxy/interceptor. Caso queiram podem pegar os fontes aqui. Esse é um projeto do eclipse que usa o plugin do Groovy.

Caso tenha lhe interessado você pode conferir outros posts relacionados com Groovy:

Popular posts from this blog

Kafka Streams with Java 15

Rust and Java Interoperability

HMAC in Java