| = Application Composer com JAX-WS and CDI |
| :index-group: Testing Techniques |
| :jbake-type: page |
| :jbake-status: published |
| |
| |
| Application Composer é uma API para criar uma aplicação EE programaticamente. Ísto é muito útil em um contexto de texto, por isso não é de admirar que se originou a partir daqui. |
| Para mais informação sobre o Application Composer, por favor acessar o link http://tomee.apache.org/tomee-8.0/docs/application-composer/index.html[Seção do Compositor de Aplicativos na documentação]. |
| |
| Neste exemplo, vamos usar o `@ApplicationComposer` no contexto de uma aplicação JAX-WS . |
| |
| == Exemplo |
| |
| Este exemplo é uma aplicação de planejamento de reuniões. É um aplicativo JAX-WS e aceita requisições para a reserva de reuniões. A aplicação primeiro verifica se a requisão pode ser reservada, se possivel, ela é reservada e retorna para o cliente se o pedido foi reservado (um valor booleano). Esta é uma aplicação simples, com propósito de demonstração, por isso é bastante simplificado. Uma solicitação de reserva é representada apenas pela data de início da reunião (um valor `java.util.Date`). |
| Uma solicitação de reserva pode ser reservada se começar após a data atual. |
| |
| A logica de negócio é implementada usando uma classe `MeetingPlannerImpl` (implementando` MeetingPlanner`). Esta classe é um serviço JAX-WS, expondo o seguinte método: `boolean book (final Date date)`. |
| O cliente vai enviar uma requisição, contendo uma data; o serviço vai retornar true ou false, se o pedido pode ser reservado. O serviço JAX-WS exposto usa, além disso, uma característica diferente, CDI, injetar uma |
| classe de serviço de lógica de negócios, verificando se a solicitação pode ser reservada. Então, quando chegar a hora de testar a anotação `@ ApplicationComposer`, verificaremos se o CDI funcionou em nossa aplicação e se o serviço JAX-WS está em execução (ou funcionando). |
| |
| A lógica de negócios que verifica se uma solicitação é registrável é definida pela seguinte interface: |
| |
| [source,java] |
| ---- |
| import java.util.Date; |
| |
| public interface Agenda { |
| boolean isBookable(Date d); |
| } |
| ---- |
| |
| A implementação é simples, sem muitos detalhes: |
| |
| [source,java] |
| ---- |
| import java.util.Date; |
| |
| public class LazyAgenda implements Agenda { |
| @Override |
| public boolean isBookable(final Date d) { |
| return d.after(new Date()); |
| } |
| } |
| ---- |
| |
| O serviço JAX-WS é definido pela seguinte interface: |
| |
| [source,java] |
| ---- |
| import javax.jws.WebMethod; |
| import javax.jws.WebService; |
| import java.util.Date; |
| |
| @WebService |
| public interface MeetingPlanner { |
| |
| @WebMethod(operationName = "book", exclude = false) |
| boolean book(final Date date); |
| } |
| ---- |
| |
| A classe que implementa essa interface é: |
| |
| [source,java] |
| ---- |
| import javax.inject.Inject; |
| import javax.jws.WebService; |
| import java.util.Date; |
| |
| @WebService |
| public class MeetingPlannerImpl implements MeetingPlanner { |
| @Inject |
| private Agenda agenda; |
| |
| @Override |
| public boolean book(final Date date) { |
| return agenda.isBookable(date); |
| } |
| } |
| ---- |
| |
| == Usando o Application Composer |
| |
| Agora, que a aplicação está completa, é hora de testa-la. Pra isto, iremos adcionar um teste unitário que ira usar o Application Composer para iniciar e fazer deploy da nossa aplicação em um ambiente Java EE Full . |
| |
| O teste completo: |
| |
| [source,java] |
| ---- |
| import org.apache.openejb.jee.WebApp; |
| import org.apache.openejb.junit.ApplicationComposer; |
| import org.apache.openejb.testing.Classes; |
| import org.apache.openejb.testing.Configuration; |
| import org.apache.openejb.testing.EnableServices; |
| import org.apache.openejb.testing.Module; |
| import org.apache.openejb.testng.PropertiesBuilder; |
| import org.apache.openejb.util.NetworkUtil; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import javax.xml.bind.JAXBContext; |
| import javax.xml.namespace.QName; |
| import javax.xml.ws.Dispatch; |
| import javax.xml.ws.Service; |
| import java.net.URL; |
| import java.util.Date; |
| import java.util.Properties; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| @EnableServices("jax-ws") |
| @RunWith(ApplicationComposer.class) |
| public class MeetingPlannerTest { |
| private static final int JAX_WS_PORT = NetworkUtil.getNextAvailablePort(); |
| |
| @Configuration |
| public Properties configuration() { |
| return new PropertiesBuilder().p("httpejbd.port", Integer.toString(JAX_WS_PORT)).build(); |
| } |
| |
| @Module |
| @Classes(cdi = true, value = {MeetingPlannerImpl.class, LazyAgenda.class}) |
| public WebApp war() { |
| return new WebApp() |
| .contextRoot("/demo") |
| .addServlet("jaxws", MeetingPlannerImpl.class.getName(), "/meeting-planner"); |
| } |
| |
| @Test |
| public void bookPort() throws Exception { |
| final Service service = Service.create( |
| new URL("http://127.0.0.1:" + JAX_WS_PORT + "/demo/meeting-planner?wsdl"), |
| new QName("http://jaxws.example.superbiz.org/", "MeetingPlannerImplService")); |
| final MeetingPlanner planner = service.getPort(MeetingPlanner.class); |
| assertTrue(planner.book(new Date(System.currentTimeMillis() + 1000000))); |
| } |
| } |
| ---- |
| |
| A primeira coisa que podemos notar é que, nós usamos o Application Composer como executor JUnit. Então, Nosso teste se integra com as ferramentas atuais, assim como qualquer outro teste JUnit. A configuração do teste é definida no método anotado com `@ Configuration`. |
| |
| A aplicação é iniciada no método tendo a annotatação `@Module` . Neste exemplo, especificamos as classes que queremos analisar e o fato de que queremos usar o CDI. |
| |
| Nosso teste faz um pedido de reserva, enviando uma data no futuro, ele verifica se a reserva está concluída. |
| |
| == Executando o teste |
| |
| Executando o teste nós podemos ver que a aplicação iniciou com sucesso, que o serviço JAX-WS está em execução e que atende corretamente as solicitações recebidas. |
| |
| [source,console] |
| ---- |
| ------------------------------------------------------- |
| T E S T S |
| ------------------------------------------------------- |
| Running org.superbiz.example.jaxws.MeetingPlannerTest |
| INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 |
| INFO - Succeeded in installing singleton service |
| INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. |
| INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) |
| INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) |
| INFO - Creating TransactionManager(id=Default Transaction Manager) |
| INFO - Creating SecurityService(id=Default Security Service) |
| INFO - Initializing network services |
| INFO - Creating ServerService(id=cxf) |
| INFO - Creating ServerService(id=httpejbd) |
| INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) |
| INFO - Initializing network services |
| INFO - ** Bound Services ** |
| INFO - NAME IP PORT |
| INFO - httpejbd 127.0.0.1 39649 |
| INFO - ------- |
| INFO - Ready! |
| INFO - Configuring enterprise application: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) |
| INFO - Auto-creating a container for bean org.superbiz.example.jaxws.MeetingPlannerTest: Container(type=MANAGED, id=Default Managed Container) |
| INFO - Creating Container(id=Default Managed Container) |
| INFO - Using directory /tmp for stateful session passivation |
| INFO - Enterprise application "/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest" loaded. |
| INFO - Creating dedicated application classloader for MeetingPlannerTest |
| INFO - Assembling app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 |
| INFO - Some Principal APIs could not be loaded: org.eclipse.microprofile.jwt.JsonWebToken out of org.eclipse.microprofile.jwt.JsonWebToken not found |
| INFO - OpenWebBeans Container is starting... |
| INFO - Adding OpenWebBeansPlugin : [CdiPlugin] |
| INFO - All injection points were validated successfully. |
| INFO - OpenWebBeans Container has started, it took 406 ms. |
| INFO - Webservice(wsdl=http://127.0.0.1:39649/demo/meeting-planner, qname={http://jaxws.example.superbiz.org/}MeetingPlannerImplService) --> Pojo(id=null./demo.jaxws) |
| INFO - Deployed Application(path=/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest) |
| INFO - Creating Service {http://jaxws.example.superbiz.org/}MeetingPlannerImplService from WSDL: http://127.0.0.1:39649/demo/meeting-planner?wsdl |
| INFO - Creating Service {http://jaxws.example.superbiz.org/}MeetingPlannerImplService from WSDL: http://127.0.0.1:39649/demo/meeting-planner?wsdl |
| INFO - Undeploying app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Stopping network services |
| INFO - Stopping server services |
| INFO - Created new singletonService org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 |
| INFO - Succeeded in installing singleton service |
| INFO - Cannot find the configuration file [conf/openejb.xml]. Will attempt to create one for the beans deployed. |
| INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) |
| INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) |
| INFO - Creating TransactionManager(id=Default Transaction Manager) |
| INFO - Creating SecurityService(id=Default Security Service) |
| INFO - Initializing network services |
| INFO - Creating ServerService(id=cxf) |
| INFO - Creating ServerService(id=httpejbd) |
| INFO - Created ServicePool 'httpejbd' with (10) core threads, limited to (200) threads with a queue of (9) |
| INFO - Initializing network services |
| INFO - ** Bound Services ** |
| INFO - NAME IP PORT |
| INFO - httpejbd 127.0.0.1 39649 |
| INFO - ------- |
| INFO - Ready! |
| INFO - Configuring enterprise application: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) |
| INFO - Auto-creating a container for bean org.superbiz.example.jaxws.MeetingPlannerTest: Container(type=MANAGED, id=Default Managed Container) |
| INFO - Creating Container(id=Default Managed Container) |
| INFO - Using directory /tmp for stateful session passivation |
| INFO - Enterprise application "/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest" loaded. |
| INFO - Creating dedicated application classloader for MeetingPlannerTest |
| INFO - Assembling app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Existing thread singleton service in SystemInstance(): org.apache.openejb.cdi.ThreadSingletonServiceImpl@49993335 |
| INFO - Some Principal APIs could not be loaded: org.eclipse.microprofile.jwt.JsonWebToken out of org.eclipse.microprofile.jwt.JsonWebToken not found |
| INFO - OpenWebBeans Container is starting... |
| INFO - Adding OpenWebBeansPlugin : [CdiPlugin] |
| INFO - All injection points were validated successfully. |
| INFO - OpenWebBeans Container has started, it took 52 ms. |
| INFO - Webservice(wsdl=http://127.0.0.1:39649/demo/meeting-planner, qname={http://jaxws.example.superbiz.org/}MeetingPlannerImplService) --> Pojo(id=null./demo.jaxws) |
| INFO - Deployed Application(path=/home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest) |
| INFO - Undeploying app: /home/bogdan/open_source/tomee-master/examples/applicationcomposer-jaxws-cdi/MeetingPlannerTest |
| INFO - Stopping network services |
| INFO - Stopping server services |
| Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.076 sec |
| |
| Results : |
| |
| Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 |
| ---- |
| |
| Um exemplo completo pode ser encontrado aqui: https://github.com/apache/tomee/tree/master/examples/applicationcomposer-jaxws-cdi[here]. |