CreateManager_pt |
|
Your trail: |
Part II: Criando novos Managers (gerentes) - Um HowTo para criação de Business Delegates que conversa com as camadas banco de dados (DAOs) e web (Struts Actions or Spring Controllers).
- Este tutorial depende da Parte I: Criando novos DAOs e Objetos no AppFuse.
Sobre este Tutorial
Este tutorial mostrará como criar uma classe que delega regras de negócio (e um teste JUnit) para conversar com o DAO que criamos na Parte I.
No contexto do AppFuse, isto é chamado de classe Manager(Gerente). Sua responsabilidade principal é agir como uma ponte entre a camada de persistência(DAO) e a camada web. O padrão Business Delegate da Sun dita que estes objetos são úteis para desacoplar a camada de apresentação da camada de dados (i.e. para aplicações Swing). Gerentes(Managers) devem ser colocados onde lógicas de negócio são necessárias.
- Vou dizer a vocês como faço as coisas no Mundo Real em textos como este.
Vamos começar criando novas classes ManagerTest e Manager na arquitetura AppFuse.
Tabela de Conteúdo
- Criar um novo ManagerTest para rodar testes JUnit no Manager
- Criar um novo Manager para conversar com o DAO
- Configurar o Spring para este Manager e as Transações
- Rodar o ManagerTest
Criar um novo ManagerTest para rodar testes JUnit no Manager
Na Parte I, criamos o objeto Person e o PersonDao - então vamos continuar a desenvolver esta entidade. Primeiramente, vamos criar o teste JUnit para o PersonManager. Crie a classe PersonManagerTest no diretório test/service/**/service. Queremos testar os mesmos métodos básicos (get, save, remove) que o nosso DAO tem.
- Isto pode parecer redundante (o porquê de todos estes testes!), mas estes testes são EXCELENTES para ter depois de 6 meses de estrada.
Esta classe deve estender BaseManagerTestCase, que já existe no pacote service. A classe pai (BaseManagerTestCase) serve para o mesmo propósito da classe BaseDaoTestCase - carregar um arquivo .properties que possui o mesmo nome de sua classe *Test, assim como inicializar o ApplicationContext do Spring.
- Usualmente eu copio (open → save as) um teste existente (i.e. UserManagerTest.java) e utilizando ctrl+f para encontrar/substituir [Uu]ser com [Pp]erson, ou qualquer que seja o nome do meu objeto.
O código abaixo é o que precisamos para um teste JUnit básico para nossos Managers. Diferente do DaoTest, este teste utiliza jMock para isolar o Manager de suas dependências e fazer um teste unitário verdadeiro.
package org.appfuse.service;
import java.util.List;
import java.util.ArrayList;
import org.appfuse.dao.PersonDao;
import org.appfuse.model.Person;
import org.appfuse.service.impl.PersonManagerImpl;
import org.jmock.Mock;
import org.springframework.orm.ObjectRetrievalFailureException;
public class PersonManagerTest extends BaseManagerTestCase {
private final String personId = "1";
private PersonManager personManager = new PersonManagerImpl();
private Mock personDao = null;
private Person person = null;
protected void setUp() throws Exception {
super.setUp();
personDao = new Mock(PersonDao.class);
personManager.setPersonDao((PersonDao) personDao.proxy());
}
protected void tearDown() throws Exception {
super.tearDown();
personManager = null;
}
}
|
Agora que temos o framework JUnit configurado para esta classe, vamos ao que interessa: os métodos de teste para nos certificar que tudo funciona no nosso Manager. Aqui está um exemplo do Tutorial DAO para ajudá-lo a entender o que estamos fazendo.
- ...criamos métodos que começam com "test" (tudo em letra minúscula). Enquanto estes métodos forem públicos, possuírem um retorno void e não possuírem argumentos, serão chamados pela nossa task <junit> em nosso arquivo build.xml do Ant. Aqui estão alguns testes simples para testar operações CRUD. Uma coisa importante para relembrar é que cada método (conhecido como teste), deve ser autônomo.
Adicione os métodos seguintes ao seu arquivo PersonManagerTest.java:
public void testGetPerson() throws Exception {
// set expected behavior on dao
personDao.expects(once()).method("getPerson")
.will(returnValue(new Person()));
person = personManager.getPerson(personId);
assertTrue(person != null);
personDao.verify();
}
public void testSavePerson() throws Exception {
// set expected behavior on dao
personDao.expects(once()).method("savePerson")
.with(same(person)).isVoid();
personManager.savePerson(person);
personDao.verify();
}
public void testAddAndRemovePerson() throws Exception {
person = new Person();
// set required fields
person.setFirstName("firstName");
person.setLastName("lastName");
// set expected behavior on dao
personDao.expects(once()).method("savePerson")
.with(same(person)).isVoid();
personManager.savePerson(person);
personDao.verify();
// reset expectations
personDao.reset();
personDao.expects(once()).method("removePerson").with(eq(new Long(personId)));
personManager.removePerson(personId);
personDao.verify();
// reset expectations
personDao.reset();
// remove
Exception ex = new ObjectRetrievalFailureException(Person.class, person.getId());
personDao.expects(once()).method("removePerson").isVoid();
personDao.expects(once()).method("getPerson").will(throwException(ex));
personManager.removePerson(personId);
try {
personManager.getPerson(personId);
fail("Person with identifier '" + personId + "' found in database");
} catch (ObjectRetrievalFailureException e) {
assertNotNull(e.getMessage());
}
personDao.verify();
}
|
Esta classe não compilará neste ponto porque nós não criamos nossa interface PersonManager.
- Acho engraçado como segui tantos padrões para permitir extendibilidade no AppFuse. Na realidade, na maioria dos projetos que participei, aprendi tanto em um ano que não queria extender a arquitetura - queria reescrevê-la. Espero que isto não ocorra tanto, utilizando minhas melhores práticas para manter o AppFuse em dia. A cada ano haverá apenas um upgrade para uma nova versão do AppFuse, ao invés de ter de reescrevê-lo. ;-)
Criar um novo Manager para conversar com o DAO
Primeiramente, crie uma interface PersonManager.java no diretório src/service/**/service, e especifique os métodos CRUD básicos para implementações posteriores. Eliminei os JavaDocs na classe abaixo para não poluir o código.
- Como sempre, duplico (open → save as) um arquivo existente (i.e. UserManager.java).
package org.appfuse.service;
import org.appfuse.model.Person;
import org.appfuse.dao.PersonDao;
public interface PersonManager {
public void setPersonDao(PersonDao dao);
public Person getPerson(String id);
public void savePerson(Person person);
public void removePerson(String id);
}
|
Agora vamos criar uma classe PersonManagerImpl que implementa os métodos da interface PersonManager. Para fazer isto, crie uma nova classe em src/service/**/service com o nome PersonManagerImpl.java. Esta classe deve estender BaseManager e implementar PersonManager.
package org.appfuse.service.impl;
import org.appfuse.model.Person;
import org.appfuse.dao.PersonDao;
import org.appfuse.service.PersonManager;
public class PersonManagerImpl extends BaseManager implements PersonManager {
private PersonDao dao;
public void setPersonDao(PersonDao dao) {
this.dao = dao;
}
public Person getPerson(String id) {
return dao.getPerson(Long.valueOf(id));
}
public void savePerson(Person person) {
dao.savePerson(person);
}
public void removePerson(String id) {
dao.removePerson(Long.valueOf(id));
}
}
|
Uma coisa que deve ser notada é o método setPersonDao. Este método é utilizado pelo Spring para ligar o PersonDao a este Gerente(Manager). Isto é configurado no arquivo applicationContext-service.xml. Veremos como se configura este arquivo no Passo 3.
Já nos é possível compilar tudo agora utilizando "ant compile-service"...
Agora necessitamos editar o arquivo de configuração do Spring para nossa camada Service para lhe dizer da existência do novo Manager.
Configurar o Spring para este Manager e as Transações
Para notificar o Spring da nossa interface PersonManager e sua implementação, abra o arquivo src/service/**/service/applicationContext-service.xml. Nele, veremos uma configuração comentada para o bean "PersonManager". Retire o comentário, ou adicione o seguinte código ao final do arquivo.
<bean id="personManager" parent="txProxyTemplate">
<property name="target">
<bean class="org.appfuse.service.impl.PersonManagerImpl" autowire="byName"/>
</property>
</bean>
|
O atributo "parent" se refere a uma definição de bean para um TransactionProxyFactoryBean, que possui todos os atributos de transação básicos inicializados.
Rodar o ManagerTest
Salve todos os seus arquivos editados e tente rodar "ant test-service -Dtestcase=PersonManager" mais uma vez.
Yeah Baby, Yeah:
BUILD SUCCESSFUL
Total time: 9 seconds
Os arquivos modificados e adicionados nesta parte podem ser baixados aqui.
Próxima: Parte III: Criando Actions e JSPs - Um tutorial para criação de Actions e JSPs na arquitetura AppFuse.
|