Archive for the ‘Java’ category

jboss.management.local:* already registered

March 28th, 2012

A exceção é da forma:

javax.management.InstanceAlreadyExistsException: jboss.management.local:<MBEAN NAME> already registered.
        at org.jboss.mx.server.registry.BasicMBeanRegistry.add(BasicMBeanRegistry.java:756)
        at org.jboss.mx.server.registry.BasicMBeanRegistry.registerMBean(BasicMBeanRegistry.java:233)
        at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
        at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:138)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)
        at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:140)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)

O JBoss, atendendo à JSR-77, registra sobre o domínio jboss.management.local todos os pacotes deployados. O problema ocorre quando dois pacotes com o mesmo nome estão presentes. A princípio isso nunca aconteceria, os OS não permitem isso. Mas o JBoss tem a capacidade de fazer deploy de pastas aninhadas, além de poder ser configurado para possuir várias pastas de deploy.

Então a solução mais simples seria alterar o nome dos pacotes (pode ser também uma Persistence Unit ou qualquer outro deployable) conflitantes. Se essa não for uma opção, é possível também desabilitar a implementação JSR-77 do JBoss, que não deve trazer maiores consequências (a não ser que esses MBeans estejam sendo explicitamente usados).

Para tanto basta remover ou desabilitar (adicionando a extensão .rej) o arquivo $JBOSS_CONF/deployers/jsr77-deployers-jboss-beans.xml

Adicionando segurança ao JBoss Messaging

March 22nd, 2012

Nesse post quero falar de como prover segurança na troca de mensagens utilizando JBoss Messaging. Segurança é um conceito bem amplo. Em termos da mensagens, o que queremos é:

  • autenticidade: garantia de que a mensagem é de quem achamos que é;
  • integridade: garantia que a mensagem é a que foi escrita originalmente;
  • confidencialidade: garantia que a mensagem não foi lida por mais ninguém.

Também não queremos que qualquer consumidor leia da fila. Portanto, além de todas essas garantias, vamos adicionar autenticação e autorização para restringir o acesso ao nosso provedor JMS.

Como alguns já devem ter notado, grande parte dos nossos requisitos são atendidos utilizado-se Certificados Digitais. E é justamente o que vamos usar.

Utilizando um canal SSL para envio de mensagens

O JBoss Messaging (JBM) utiliza um subprojeto da JBoss chamado JBoss Remoting para comunicação de rede. Para utilizarmos SSL, basta configurar o conector do JBoss Remoting para utilizar um socket SSL. Para nossa sorte a equipe da JBoss já fez isso para nós, basta copiar o arquivo $JBOSS_HOME/docs/examples/jms/remoting-sslbisocket-service.xml para a pasta de deploy.

Será preciso criar um Keystore $JBOSS_HOME/server/default/conf/messaging.keystore com a par de chaves e o certificado. Se o certificado for auto-assinado, será também preciso adicioná-lo Truststore do cliente. A senha do Keystore deve ser “secureexample”.

Para produção é possível alterar configurações de keystore e senha no MBean org.jboss.remoting.security.SSLSocketBuilder, dentro do arquivo remoting-sslbisocket-service.xml que copiamos.

Feito isso, vamos criar um ConnectionFactory que utilize esse conector. Dentro de deploy, crie um arquivo messaging-secure-socket-service.xml:

<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean code="org.jboss.jms.server.connectionfactory.ConnectionFactory"
          name="jboss.messaging.destination:service=SecureConnectionFactory"
          xmbean-dd="xmdesc/ConnectionFactory-xmbean.xml">
 
      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
      <depends optional-attribute-name="Connector">jboss.messaging:service=Connector,transport=sslbisocket</depends>
 
      <attribute name="JNDIBindings">
         <bindings>
            <binding>/SecureConnectionFactory</binding>
         </bindings>
      </attribute>
   </mbean>
</server>

Note que o atributo Connector possui o Name do MBean que utiliza o conector SSL. Estamos informando para o JBoss que esse ConnectionFactory deve utilizar um canal SSL. Sempre que o client utilizar um ConnectionFactory obtido pelo lookup de “/SecureConnectionFactory” estará se comunicando em um canal encriptado.

NOTA: cuidado para não utilizar binds JNDI padrões do JBM, definidos em connection-factories-service.xml. Eles usam o jboss.messaging:service=Connector,transport=bisocket, que não utiliza Certificado.

Configurando autenticação/autorização para filas

Para autenticar o client vamos utilizar usuário/senha. O JBM por padrão utiliza o Security Domain “messaging” definido em messaging-jboss-beans.xml, que utiliza datasource DefaultDS. Nesse mesmo arquivo é possível alterar o Security Domain utilizado.

As definições de autorização devem ser feitas por fila. Ao definir uma fila, devemos fazê-lo da seguinte forma:

<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean code="org.jboss.jms.server.destination.QueueService"
      name="jboss.messaging.destination:service=Queue,name=securityTestQueue"
      xmbean-dd="xmdesc/Queue-xmbean.xml">
 
      <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
      <depends>jboss.messaging:service=PostOffice</depends>
      <attribute name="SecurityConfig">
         <security>
            <role name="guest" read="false" write="false" create="false" />
            <role name="publisher" read="true" write="true" create="true" />
         </security>
      </attribute>
   </mbean>
</server>

Note o atributo SecurityConfig. Acho que é tudo bem auto-explicativo, a não ser o create. Esse atributo se aplica a tópico e dá o privilégio do client criar uma subscrição DURABLE.

O para publicar na fila, o client deve obter uma conexão usando a chamada createConnection() que passa usuário e senha:

javax.jms.ConnectionFactory.createConnection(username, password);

NOTA: cuidado ao utilizar os arquivos *-persistence-service.xml que vêm de exemplo no JBoss. Alguns usuário padrões são definidos neles e podem ser utilizados para obter acesso privilegiado. Em um post anterior postei mais informações sobre o JBoss Messaging.

Criando um MDB para consumir

Para consumir mensagens autenticando-se e utilizando o ConnectionFactory sobre SSL, o MDB deve ser configurado com algumas propriedade a mais:

@MessageDriven(activationConfig =
{
   @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
   @ActivationConfigProperty(propertyName="destination", propertyValue="queue/securityTestQueue"),
   @ActivationConfigProperty(propertyName="ConnectionFactoryName", propertyValue="SecureConnectionFactory"),
   @ActivationConfigProperty(propertyName="user", propertyValue="john"),
   @ActivationConfigProperty(propertyName="password", propertyValue="needle")
})
public class QueueConsumer implements MessageListener {
   public void onMessage(Message message) {
      System.out.println(this.getClass().getName() + " -> " + message);
   }
}

That’s it!

Devoxx 2011

November 23rd, 2011

EDIT: saiu o artigo na InfoQ BR

De volta do Devoxx! O evento foi muito bom. De longe o maior, mais alto nível, melhor organizado evento que já fui.

Minha palestra aconteceu na quarta e qual foi minha surpresa ao ver o Pete Muir (Seam/Weld/Arquillian), Dan Allen (Seam/Weld/Arquillian) e Aslak Knutsen (Arquillian lead) sentados na primeira fileira!

O mais legal foi ter conversado com eles e eles terem me mostrado que a proposta que apresentei já está no road map do Arquillian. Legal!

O evento foi uma ótima oportunidade para fazer networking. Além do convite para um brainstorm regado a cerveja belga do time do Arquillian, encontrei os brazucas Yara e o Vinícus Senger lá também.

Outra pessoa com quem estava querendo trocar umas idéias é o Mathieu Ancelin, criador do weld-osgi, idéia que eu há muito queria implementar e ele fez eximiamente.

Deve estar saindo nos proximos dias um artigo que escrevi para a InfoQ BR sobre a cobertura do Devoxx. Quando sair post o link aqui. Também disponibilizei os slides da palestra no Slideshare.

TDC e Devoxx

October 16th, 2011

Esse mês e o próximo estarei palestrando no TDC e no Devoxx.

A edição Goiânia do TDC vai acontecer dias 29 e 30, e de novo estarei lá palestrando.

Sábado, dia 29/10, às 17:40 estarei falando sobre o Weld/CDI. Será uma palestra introdutória onde quero mostrar alguns recursos que temos e aplicações interessantes deles. Será uma versão mais básica da palestra que farei no Devoxx, e será focada em testes.

No domingo às 14:10 foi mostrar o Drools, a apresentação será similar à do TDC São Paulo, mas vou tentar me organizar melhor para mostrar todas as demos que tinha planejado mostrar :) Apareçam, prometo que vai ser interessante!

Em Novembro estarei na Bélgica para o Devoxx, que será uma semana inteira dedicada a tecnologia com representantes da Red Hat, Oracle, Adobe, Google, HP, IBM, SrpingSource e outros.

Lá vou fazer uma rápida palestra na quinta, dia 17/11, às 13:15. Vou falar como TDD combina com CDI: quais são os problemas enfrentados e quais alternativas temos. Terá um pouco de Weld, portable extensions e Arquillian. Aos brazucas que estiverem por lá, vamos combinar uma cerveja depois!

Maven é realmente tão ruim assim?

September 20th, 2011

Estava para escrever um post mas ia entrar numa discussão de maven haters e lovers então resolvi esclarecer as coisas antes. Não entendo esse pessoal que odeia maven.

Reclamam: maven baixa toda a internet

Acho que quem reclama não entende muito como funciona o sistema de dependências do maven. O maven não faz (muita) mágica. O dono do artefato tem que definir as dependências do artefato.

Ou seja, de duas uma: ou o maven está baixando a internet porque os mantenedores doas artefatos foram relapsos ou realmente todas aquelas dependências eram necessárias.

Se foi preguiça do desenvolvedor, não é culpa do maven. Todos conhecemos sistemas de empacotamento (port, portage, agt, yum) e sabemos que tem muito mantenedor preguiçoso que, em vez de deixar as dependências enxutas, põe tudo como dependência para poupar dor de cabeça. Onde está o problema do maven aqui? Maven é uma ferramenta, ele faz o que for mandado.

Se é porque realmente existiam muitas dependências, ai não tem o que falar mesmo. Provavelmente esse pessoal que reclama nunca entrou site por site, procurando os binários, lendo documentação de que versão é compatível com que versão. Só de me poupar esse trabalho, mesmo com pom’s totalmente bagunçados, que baixam o repositório inteiro, para mim vale a pena usar maven. Dica: você não precisa ficar olhando o terminal esperando tudo ser baixado.

E ele baixa cada pacote uma única vez, é muito choro por pouca coisa. Além do disso, coisas que parar mim salvam muito tempo e o pessoal não pensa..

Não pensam: baixa dependências (transitivas!)

Agora com o Ivy isso já não é tão extraordinário, mas o Ivy foi provocado pelo Maven. Aliás, o Ivy usa os repositórios do Maven! Nunca usei o Ivy, mas para mim isso significa que ele também irá baixar toda a internet.

Não pensam: analisar source de pacotes

Já teve que decompilar classes com o jad (ou qualquer outra ferramenta) para debugar código? Quem já fez isso percebeu que é um pé no saco ter que decompilar todas as classes que formam a stack (e provavelmente mais) e ainda ter os números de linha todos bagunçados impedindo de usar o source na IDE para setar break points. Ou isso ou você procurava o source para baixar (de novo, procurando site em site) quando não tinha que fazer checkout de SCM e tendo que achar a tag certinha!

Não pensam: tooling

Já usou o m2eclipse (o antigo, antes da Sonar doar pra Eclipse)? Quando trabalhava em fábrica lembro o terror e pânico quando alguém commitava o .project, era ficar ajustando classpath um bom tempo. E tem algo mais porco que versionar JARs? Busca JARs, adiciona projetos dependentes ao classpath sem precisar dar build, mostra a árvore de dependência, o pom efetivo. Ele tem bugs sim, mas nem de longe vale a pena deixar de usá-lo por causa disso.

Para os que reclamam: Everythings Amazing & Nobodys Happy

Tente parar de usá-lo para ver o quanto vão dar valor a ele.

Weld no Tomcat 7

May 29th, 2011

Havia escrito há muito tempo atrás como fazer o deploy de uma aplicação Seam no Tomcat. Daquele tempo para cá muita coisa mudou: o Seam junto com outros frameworks de IoC gerou a JSR-299 de Contexts and Dependency Injection (CDI), a JBoss criou o Weld (implementação de referência CDI), o Seam 3 foi lançado baseado na nova especificação.

Com a padronização numa JSR, agora implementações CDI são obrigadas a suportar uma variedade maior de ambientes de forma vendor neutral. O Weld faz isso e entre os ambientes suportados está o Tomcat. Portanto não há necessidade de configurações extras e gambiarras! O próprio projeto Weld provê archetypes maven com várias configuração, para criar uma aplicação para rodar em um servlet container:

mvn archetype:generate -DarchetypeArtifactId=weld-jsf-servlet-minimal \
                       -DarchetypeGroupId=org.jboss.weld.archetypes \
                       -DarchetypeVersion=1.0.0.Beta1 \
                       -DarchetypeRepository=central

E um projeto pronto para ser executado no Tomcat/Jetty será criado. O problema é que, devido a um bug, no Tomcat 7 pode ser que você veja a seguinte exceção:

SEVERE: Exception sending context initialized event to listener instance of class org.jboss.weld.environment.servlet.Listener
java.lang.NoClassDefFoundError: org/apache/AnnotationProcessor
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2820)
	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1143)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1638)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2820)
	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1143)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1638)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	at org.jboss.weld.environment.tomcat.Tomcat6Container.initialize(Tomcat6Container.java:47)
	at org.jboss.weld.environment.servlet.Listener.contextInitialized(Listener.java:184)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4544)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5016)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1035)
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:738)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1035)
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:289)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:442)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:674)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:596)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:303)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)
Caused by: java.lang.ClassNotFoundException: org.apache.AnnotationProcessor
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1671)
	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1516)
	... 36 more

O problema é que o Weld identifica erroneamente o Tomcat 7 como Tomcat 6. Para resolver o problema podemos definir explicitamente que o container que estamos usando é o Tomcat 7. Isso é feito criando-se um arquivo META-INF/services/org.jboss.weld.environment.Container no classpath com o conteúdo:

org.jboss.weld.environment.tomcat7.Tomcat7Container

Note que estamos definindo na mão o container! Ou seja, abrimos mão da portabilidade. Vamos esperar o bug ser corrigido, mas até lá é isso!

Referência: https://issues.jboss.org/browse/WELD-879

Abertas inscrições para o JBoss In Bossa 2010

April 10th, 2010

Ainda que tarde, vale a pena anunciar.

Foram abertas as incrições para o JBoss In Bossa 2010 que acontecerá em São Paulo dias 7 e 8 de maio. O evento é o maior da América Latina relacionado a JBoss e contará com a presença de palestrantes internacionais como o Peter Muir (project lead do Seam e do Weld), Benjamin Mestrallet (CEO da eXo Platform) e Mauricio Salatino (CTO da PlugTree).

Veja alguns dos principais assuntos previstos na agenda:

  • O novo JBoss 6
  • Tuning JBoss
  • Java Persistence API
  • Seam
  • Weld
  • Contexts and Dependency Injection
  • Java ServerFaces 2.0
  • Teiid
  • Drools
  • Jopr
  • E a lista continua..

É uma ótima oportunidade para conhecer pessoalmente alguns nomes de peso na comunidade e fazer networking. Se inscreva!

Acompanhe também o evento via @jbossinbossa.

Implementando testes com mock objects

July 20th, 2009

Ok, estou convencido que usar mock objects é uma boa idéia mas como faço isso? A princípio não é qualquer código que está pronto para ser testado usando-se mocks, ele precisa ser escrito de uma forma a possibilitar isso.

No geral escrever código de tal forma que seja testável é uma boa prática e indica que ele segue alguns princípios de projeto que o tornam fracamente acoplado, aumentam sua manutenibilidades, etc.

Vejamos um exemplo de código que deva ser alterado para se tornar testável:

public class CustomerFacade {
 
	private CustomerDao customerDao;
 
	public CustomerFacade() {
		customerDao = new CustomerDaoImpl();
	}
 
	public void hireCustomer(Custumer custumer) { ... }
 
	public void fireCustomer(Custumer custumer) { ... }
 
}

Como já devo ter dito, não sou muito bom de exemplos.. Mas acho que esse ai está bem ilustrativo, embora para alguns DAO possa parecer meio arcaico. Deixei as reticências para a imaginação de vocês.

Existem 3 formas de se alterar esse código, as duas primeiras se usam de técnicas de bom projeto e melhoram a qualidade do software:

1. Dependency Injection (DI)

O mais simples e limpo. Foi a forma usada para injetar os mocks no exemplo do post passado:

public class CustomerFacade {
 
	private CustomerDao customerDao;
 
	public void setCustomerDAO(CustomerDao customerDao) {
		this.customerDao = customerDao;
	}
 
	public void hireCustomer(Custumer custumer) { ... }
 
	public void fireCustomer(Custumer custumer) { ... }
}

Basta agora, na hora de testar injetar não o componente real, mas seu mock.

public class CustomerFacadeTest {
    private Mockery context = new Mockery();
 
    public CustomerFacadeTest() {
    	context = new Mockery();
    }
 
    @Test
    public void testHire() throws Exception {
        // set up mock
    	final CustomerDao customerDao = context.mock(CustomerDao.class);
 
        // test state
    	CustomerFacade customerFacade = new CustomerFacade();
    	customerFacade.setCustomerDAO(customerDao);
 
        // expectations
        context.checking(new Expectations(){{
	        oneOf(customerDao).save(12);
        }});
 
        // execute
        customerFacade.hireCustomer(new Custumer(12));
 
        // verify
        context.assertIsSatisfied();
    }
 
}

2. Factory Method

Uma técnica um pouco mais embolada mas que ainda assim trás melhorias para o código consiste na extração de um Factory Method:

public class CustomerFacade {
 
	private CustomerDao customerDao;
 
	public CustomerFacade() {
		customerDao = createCustomerDao();
	}
 
	protected CustomerDao createCustomerDao() {
		return new CustomerDaoImpl();
	}
 
	public void hireCustomer(Custumer custumer) { ... }
 
	public void fireCustomer(Custumer custumer) { ... }
 
}

Notem que o createCustomerDao() é protected, isso porque na hora de usá-lo nos testes vamos estender essa classe e sobrescrever o createCustomerDao() para retornar um mock:

public class CustomerFacadeTest {
    private Mockery context = new Mockery();
 
    public CustomerFacadeTest() {
    	context = new Mockery();
    }
 
    @Test
    public void testHire() throws Exception {
        // set up mock
    	final CustomerDao customerDao = context.mock(CustomerDao.class);
 
        // test state
    	CustomerFacade customerFacade = new CustomerFacade() {
 
		@Override
		protected CustomerDao createCustomerDao() {
			// return the mock instead!!
			return customerDao;
		}
 
    	};
 
        // expectations
        context.checking(new Expectations(){{
	        oneOf(customerDao).save(12);
        }});
 
        // execute
        customerFacade.hireCustomer(new Custumer(12));
 
        // verify
        context.assertIsSatisfied();
    }
 
}

3. Aspect Oriented Programming

Essa é uma técnica workaround, e é para quando realmente não há jeito de usar-se as outras técnicas. Com ela não é preciso alterar código algum, apenas criar um point cut que intercepte a instanciação do CustomerDaoImpl. O test case é o seguinte:

public class CustomerFacadeTest {
	private Mockery context = new Mockery();
	private CustomerDaoImpl customerDao;
 
	public CustomerFacadeTest() {
		context = new Mockery();
		// so we can mock a concrete class
		context.setImposteriser(ClassImposteriser.INSTANCE);
 
		customerDao = context.mock(CustomerDaoImpl.class);
	}
 
	// returns the mock instance in test context
	public CustomerDaoImpl getCustomerDao() {
		return customerDao;
	}
 
	@Test
	public void testHire() throws Exception {
		// test state
		CustomerFacade customerFacade = new CustomerFacade();
 
		// expectations
		context.checking(new Expectations(){{
			oneOf(customerDao).save(12);
		}});
 
		// execute
		customerFacade.hireCustomer(new Custumer(12));
 
		// verify
		context.assertIsSatisfied();
	}
 
	public String print() {
		return("adasda");
	}
 
}

E criando-se o aspecto em AspectJ:

public aspect InstanciatingAspect{
 
	// intercept only from CustomerFacadeTest
	pointcut testing(Object test) :
		this(test) &&
		execution(public void CustomerFacadeTest.*());
 
	// intercept CustomerDaoImpl instantiations
	pointcut instanciateCustomerDao(Object test) :
		cflow(testing(test)) &&
		call(CustomerDaoImpl.new(..));
 
	Object around(Object test) : instanciateCustomerDao(test) {
		// get a hold of the mock instance made public by our test case
		CustomerDaoImpl customerDaoImpl = ((CustomerFacadeTest) test).getCustomerDao();
		// return the mock reference instead
		return customerDaoImpl;
	}
}

Como visto, a única dificuldade é que o aspecto deve retornar uma instância do mock que tenha sido criada no contexto do test case.Para tanto instanciamos o mock no test case e o tornamos acessível através do getCustomerDao(). Feito isso, ao interceptarmos no aspecto a criação do CustomerDaoImpl() nós a substituímos pela referência obtida do test case.

Estrutura de um projeto Seam

August 30th, 2008

O seam-gen é um gerador de scaffolding muito útil para quem programa em Seam. O seam-gen em si é uma ferramenta CLI, mas o JBoss Tools nos dá uma GUI para facilitar nossa vida. Bom, então o primeiro passo é instalar o plugin do JBoss Tools. É só baixar do site deles e descompactar no diretório do Eclipse, nada de mais.

Você notará que serão adicionadas várias perspectivas, entre elas, a Seam. Vamos selecionar essa perspectiva e criar um novo Seam Project. Com isso já temos um projeto funcional com segurança, apresentação de erros, e conexão com banco de dados. Também é criado um projeto <projeto>-Test para testes. Vamos entender um pouco do que nos foi gerado.

  1. classe usada pelo Seam para autenticaçãoseam-gen-structure
  2. arquivo chave. Indica ao Seam que ele deve procurar nesse diretório por componentes
  3. persistence.xml do JPA
  4. arquivo com algumas propriedados a serem substituidas pelo Ant no components.xml
  5. import.sql do Hibernate
  6. mensagens para internacionalização
  7. arquivo Drools com regras de autorização
  8. datasource gerado para o JBoss
  9. arquivo de configuração do Seam (componentes, integração)
  10. arquivo de configuração WAR do JBoss
  11. arquivo de configuração do Seam (regras de fluxo, segurança, controle de conversação)
  12. similar ao arquivo pages.xml, mas específico para o login.xhtml
  13. arquivo de configuração do plugin Hibernate Console

Vamos ver por alto algumas configurações interessantes. Na parte de segurança temos no components.xml:

<event type="org.jboss.seam.security.notLoggedIn">
<action execute="#{redirect.captureCurrentView}"/>
</event>
<event type="org.jboss.seam.security.loginSuccessful">
<action execute="#{redirect.returnToCapturedView}"/>
</event>

O Seam possui o conceito de eventos. Eventos são mensagens que podem ser capturadas ou lançadas, no estilo broadcast. O Seam em si lança vários eventos e podemos capturar esses eventos através de XML, como no exemplo acima. O trecho acima está invocando métodos do componente built-in #{redirect} quando eventos de segurança forem lançados. Ele especifica que a view id JSF deve ser salva quando o usuário não-logado tentar acessar uma página restrita e que essa view id deve ser restaurada uma vez que ele se autentique.
Um outro trecho especifica que componente é responsável pela autenticação:

<security:identity authenticate-method="#{authenticator.authenticate}"
security-rules="#{securityRules}"
remember-me="true"/>

E no pages.xml dizemos que página deve ser utilizada para login:

<exception class="org.jboss.seam.security.NotLoggedInException">
<redirect view-id="/login.xhtml">
<message>Please log in first</message>
</redirect>
</exception>

Aqui temos um tratamento de exceção bem parecido com o de servlets que definimos no web.xml. O usuário será redirecionado para a página login.xhtml e uma mensagem JSF será adicionada.
Se olharmos no login.pages.xml vemos ainda:

<navigation from-action="#{identity.login}">
<rule if="#{identity.loggedIn}">
<redirect view-id="/home.xhtml"/>
</rule>
</navigation>

O que nos lembra bastante as navigation rules JSF. De fato parecem muito, mas as extendem em funcionalidade, podendo não só enviar o usuário para outra página como também lançar um evento, executar um método para avaliar qual será a próxima página, e algumas coisas mais avançadas.

O objetivo desse post é apenas nos familiarizar mais com o Seam e dar uma visão sobre o scaffold que nos foi gerado de base e que iremos usar para desenvolver nossa aplicação. Ainda vamos falar com mais detalhes de eventos, componentes e configurações.

Parte I: O que é Seam?

August 12th, 2008

Como recebo vários hints no post JBoss Seam no Tomcat, resolvi escrever mais sobre Seam. Esse post abre uma série de tutoriais de Seam.

Seam é um framework muito amplo. Pegue alguns dos frameworks mais representativos, ponha algumas práticas de desenvolvimento e misture: assim que vejo o Seam. O Seam em sua plenitude usa os frameworks: EJB3, JSF, Facelets, Hibernate, Hibernate Validations, Richfaces, Ajax4JSF, jBPM, Drools (qualquer associação ao nome JBoss é mera coincidência). É muita coisa. Mas ele não só usa esses frameworks, ele também provê uma integração entre eles, disponibiliza componentes built-in (à la Spring, cujo qual inclusive pode-se integrar) e introduz algumas melhorias sobre eles. Além disso ele apregoa algumas práticas como desenvolvimento orientado a componentes e desencoraja outras, como desenvolvimento em camadas.

Vou deixar de lado o que cada framework faz, pois não entra no mérito do que o Seam tem a oferecer. Dando um enfoque bem prático, o Seam:

  • Reduz plumbing code do JSF. Quem já programou com JSF sabe do que estou falando (Não? FacesContext? faces-config.xml?).
  • Resolve o infame problema do “back button” em JSF. E reload, e bookmarking, e …
  • Facilita o uso de JPA. Tem um código cheio de merges()? Usa uma long-running transaction num page flow?
  • Possibilita page flows usando o jBPM.
  • Permite aplicações multi-windows. E finalmente poder clicar “Abrir em nova janela” nos links!
  • Permite o uso de workspaces. Como no Linux.
  • Faz uso extensivo de anotações. Mas também permiti o uso de XML.
  • Possui uma penca de tags JSF. Uns muito úteis, uns bem exóticos…
  • E muito mais!

Dada essa introdução, vou detalhar nos próximos posts cada um desses itens dizendo como realizamos eles com o uso so Seam. Esse blog não é sobre Seam, então esperem outros posts no meio. Até mais!

referência: http://docs.jboss.com/seam/latest/reference/en-US/html/Book-Preface.html