| :index-group: JMS and MDBs |
| :jbake-type: page |
| :jbake-status: status=published |
| |
| = Simples JMS |
| Este exemplo demonstra como configuar um serviço JMS personalizado ``CustomJmsService`` para produzir e consumir uma mensagem JMS ``Message`` . |
| |
| = Código |
| |
| == Os serviços JMS: ``Message``, ``Queue``, MessageProducer``, ``MessageConsumer`` |
| Aqui temos um endpoint REST, uma classe com a anotação ``@Path("/ message")`` que indica a rota correspondente a classe ``CustomJmsService``. Portanto, definimos ``sendMessage()`` como ``@POST`` e ``acceptMessage()`` como ``@GET`` para a rota ``/message``. |
| |
| Além disso, diretamente relacionado a este exemplo, você pode ver 2 elementos: uma fila: ``Queue'' e uma fábrica de conexão: ``ConnectionFactory'' anotada com ``@Resource'' |
| |
| Finalmente, interagindo com instâncias de ``Connection'', ``Session'' e ``Queue'', você pode ver instâncias de ``MessageProducer'' e ``MessageConsumer'', responsáveis por escrever e ler de/para o fila: ``Queue`` respectivamente. |
| |
| [source,java] |
| ---- |
| @Stateless |
| @Path("message") |
| public class CustomJmsService { |
| |
| @Resource(name = "messageQueue") |
| private Queue messageQueue; |
| |
| @Resource |
| private ConnectionFactory connectionFactory; |
| |
| @POST |
| public void sendMessage(final String message) { |
| sendMessage(messageQueue, message); |
| } |
| |
| @GET |
| public String receiveMessage() throws JMSException { |
| final TextMessage textMessage = receiveMessage(messageQueue, 1000); |
| if (textMessage == null) { |
| return null; |
| } |
| |
| return textMessage.getText(); |
| } |
| |
| private void sendMessage(final Queue queue, final String message) { |
| try (final Connection connection = connectionFactory.createConnection(); |
| final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); |
| final MessageProducer producer = session.createProducer(queue)) { |
| |
| connection.start(); |
| |
| final Message jmsMessage = session.createTextMessage(message); |
| |
| // Isso enfileira mensagens com êxito com 8.0.0-M3 e 8.0.0 |
| producer.send(jmsMessage); |
| } catch (final Exception e) { |
| throw new RuntimeException("Caught exception from JMS when sending a message", e); |
| } |
| } |
| |
| private TextMessage receiveMessage(final Queue queue, final long receiveTimeoutMillis) { |
| try (final Connection connection = connectionFactory.createConnection(); |
| final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); |
| final MessageConsumer messageConsumer = session.createConsumer(queue)) { |
| |
| connection.start(); |
| |
| final Message jmsMessage = messageConsumer.receive(receiveTimeoutMillis); |
| |
| if (jmsMessage == null) { |
| return null; |
| } |
| |
| return (TextMessage) jmsMessage; |
| } catch (final Exception e) { |
| throw new RuntimeException("Caught exception from JMS when receiving a message", e); |
| } |
| } |
| } |
| |
| ---- |
| |
| == Testando |
| |
| === Teste para o serviço JMS |
| |
| O teste é trivial. A ideia é primeiro fazer uma solicitação POST que contenha a mensagem do serviço. Isso é feito usando instâncias das classes ``ClientBuilder'' e ``WebTarget''. |
| |
| Em seguida, semelhante à solicitação POST, é feita uma solicitação GET que consome a mensagem anterior. |
| |
| Por fim, verifica-se o status HTTP das respostas para que sejam equivalentes aos códigos HTTP esperados (204/200), bem como que o conteúdo da mensagem recebida seja igual ao da mensagem enviada. |
| |
| |
| [source,java] |
| ---- |
| @RunWith(Arquillian.class) |
| @RunAsClient |
| public class CustomJmsServiceTest { |
| |
| @Deployment |
| public static Archive<?> deployment() { |
| return Mvn.war(); |
| } |
| |
| @ArquillianResource |
| private URL baseUrl; |
| |
| @Test |
| public void test() throws Exception { |
| // POST |
| { |
| final WebTarget webTarget = ClientBuilder.newClient().target(baseUrl.toURI()); |
| final Response response = webTarget.path("message").request().post(Entity.text("This is a test")); |
| |
| assertEquals(204, response.getStatus()); |
| } |
| |
| // GET |
| { |
| final WebTarget webTarget = ClientBuilder.newClient().target(baseUrl.toURI()); |
| final Response response = webTarget.path("message").request().get(); |
| assertEquals(200, response.getStatus()); |
| |
| final String content = response.readEntity(String.class); |
| assertEquals("This is a test", content); |
| } |
| } |
| } |
| ---- |
| |
| |
| === Executando o teste de serviço JMS |
| |
| Construir e testar o exemplo é simples. No diretório ``simple-jms`` você deve executar: |
| |
| [source,java] |
| ---- |
| $ mvn clean install |
| ---- |
| |
| Isso criará uma saída semelhante à seguinte: |
| |
| [source,java] |
| ---- |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication Using writers: |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter@7a6a8b01 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.nio.NioMessageBodyWriter@58be749c |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.StringTextProvider@2740b6d6 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.JAXBElementTypedProvider@e08fc09 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.PrimitiveTextProvider@139e9988 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.FormEncodingProvider@3cee7c7e |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.MultipartProvider@2513f485 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.SourceProvider@778a8c93 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.JAXBElementProvider@414a7c3a |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonbProvider@1b4e4173 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.openejb.server.cxf.rs.johnzon.TomEEJsonpProvider@3f1bfc2e |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.BinaryDataProvider@7dc57a14 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.provider.DataSourceProvider@1af0fefd |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication Using exception mappers: |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper@8e6f08b |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.openejb.server.cxf.rs.EJBExceptionMapper@2fcd3c |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.deployApplication org.apache.cxf.jaxrs.validation.ValidationExceptionMapper@1979c922 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints REST Application: http://localhost:6586/test/ -> org.apache.openejb.server.rest.InternalApplication@2653d780 |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints Service URI: http://localhost:6586/test/message -> EJB org.superbiz.jms.CustomJmsService |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:6586/test/message -> String receiveMessage() throws JMSException |
| INFO [http-nio-6586-exec-2] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints POST http://localhost:6586/test/message -> void sendMessage(String) |
| INFO [http-nio-6586-exec-5] org.apache.activemq.broker.TransportConnector.start Connector vm://localhost started |
| org.apache.openejb.client.EventLogger log |
| INFO: RemoteInitialContextCreated{providerUri=http://localhost:6586/tomee/ejb} |
| INFO [http-nio-6586-exec-8] org.apache.openejb.assembler.classic.Assembler.destroyApplication Undeploying app: /tomee/examples/simple-jms/target/arquillian-test-working-dir/0/test |
| WARNING [http-nio-6586-exec-8] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [test] appears to have started a thread named [PoolIdleReleaseTimer] |
| WARNING [http-nio-6586-exec-8] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [test] appears to have started a thread named [ActiveMQ VMTransport: vm://localhost#0-1] |
| WARNING [http-nio-6586-exec-8] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [test] appears to have started a thread named [ActiveMQ VMTransport: vm://localhost#0-2] |
| org.apache.openejb.arquillian.common.TomEEContainer undeploy |
| INFO: cleaning /tomee/examples/simple-jms/target/arquillian-test-working-dir/0/test.war |
| org.apache.openejb.arquillian.common.TomEEContainer undeploy |
| INFO: cleaning /tomee/examples/simple-jms/target/arquillian-test-working-dir/0/test |
| Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 27.962 sec |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke A valid shutdown command was received via the shutdown port. Stopping the Server instance. |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Pausing ProtocolHandler ["http-nio-6586"] |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Pausing ProtocolHandler ["ajp-nio-8009"] |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Stopping service [Catalina] |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Stopping ProtocolHandler ["http-nio-6586"] |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Stopping ProtocolHandler ["ajp-nio-8009"] |
| INFO [main] org.apache.openejb.server.SimpleServiceManager.stop Stopping server services |
| INFO [main] org.apache.openejb.assembler.classic.Assembler.destroyApplication Undeploying app: openejb |
| SEVERE [main] org.apache.openejb.core.singleton.SingletonInstanceManager.undeploy Unable to unregister MBean openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,EJBModule=openejb,SingletonSessionBean=openejb/Deployer,name=openejb/Deployer,j2eeType=Invocations |
| SEVERE [main] org.apache.openejb.core.singleton.SingletonInstanceManager.undeploy Unable to unregister MBean openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,EJBModule=openejb,SingletonSessionBean=openejb/Deployer,name=openejb/Deployer,j2eeType=Invocations |
| INFO [main] org.apache.openejb.assembler.classic.Assembler.doResourceDestruction Closing DataSource: Default Unmanaged JDBC Database |
| INFO [main] org.apache.openejb.assembler.classic.Assembler.doResourceDestruction Stopping ResourceAdapter: Default JMS Resource Adapter |
| INFO [main] org.apache.openejb.resource.activemq.ActiveMQResourceAdapter.stop Stopping ActiveMQ |
| INFO [108] org.apache.openejb.resource.activemq.ActiveMQResourceAdapter.stopImpl Stopped ActiveMQ broker |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Destroying ProtocolHandler ["http-nio-6586"] |
| INFO [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Destroying ProtocolHandler ["ajp-nio-8009"] |
| |
| Results : |
| |
| Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 |
| |
| [INFO] |
| [INFO] --- maven-war-plugin:2.4:war (default-war) @ simple-jms --- |
| [INFO] Packaging webapp |
| [INFO] Assembling webapp [simple-jms] in [/tomee/examples/simple-jms/target/simple-jms-8.0.1-SNAPSHOT] |
| [INFO] Processing war project |
| [INFO] Webapp assembled in [2118 msecs] |
| [INFO] Building war: /tomee/examples/simple-jms/target/simple-jms-8.0.1-SNAPSHOT.war |
| [INFO] |
| [INFO] --- maven-install-plugin:2.4:install (default-install) @ simple-jms --- |
| [INFO] Installing /tomee/examples/simple-jms/target/simple-jms-8.0.1-SNAPSHOT.war to /.m2/repository/org/superbiz/simple-jms/8.0.1-SNAPSHOT/simple-jms-8.0.1-SNAPSHOT.war |
| [INFO] Installing /tomee/examples/simple-jms/pom.xml to /.m2/repository/org/superbiz/simple-jms/8.0.1-SNAPSHOT/simple-jms-8.0.1-SNAPSHOT.pom |
| [INFO] ------------------------------------------------------------------------ |
| [INFO] BUILD SUCCESS |
| [INFO] ------------------------------------------------------------------------ |
| [INFO] Total time: 50.089 s |
| ---- |
| |
| === Executando a aplicação |
| |
| Executar o exemplo é simples. No diretório ``simple-jms`` digite: |
| |
| [source,java] |
| ---- |
| $ mvn tomee:run |
| ---- |
| |
| Isso criará uma saída semelhante à seguinte. |
| |
| [source,java] |
| ---- |
| [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints REST Application: http://localhost:8080/simple-jms-8.0.1-SNAPSHOT/ -> org.apache.openejb.server.rest.InternalApplication@3b8b5b40 |
| [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints Service URI: http://localhost:8080/simple-jms-8.0.1-SNAPSHOT/message -> EJB org.superbiz.jms.CustomJmsService |
| [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8080/simple-jms-8.0.1-SNAPSHOT/message -> String receiveMessage() throws JMSException |
| [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints POST http://localhost:8080/simple-jms-8.0.1-SNAPSHOT/message -> void sendMessage(String) |
| [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Deployment of web application archive [\tomee\examples\simple-jms\target\apache-tomee\webapps\simple-jms-8.0.1-SNAPSHOT.war] has finished in [8,264] ms |
| [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesRmiTargets] to [true] as the property does not exist. |
| [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesObjectStreamClassCaches] to [true] as the property does not exist. |
| [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesObjectStreamClassCaches] to [true] as the property does not exist. |
| [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesThreadLocals] to [true] as the property does not exist. |
| [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Starting ProtocolHandler ["http-nio-8080"] |
| [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Starting ProtocolHandler ["ajp-nio-8009"] |
| [main] sun.reflect.DelegatingMethodAccessorImpl.invoke Server startup in [8,367] milliseconds |
| ---- |
| |
| |
| NOTE: É possível usar o comando CURL`` (ou uma ferramenta cliente) para enviar uma solicitação POST e então uma solicitação GET para a URL do serviço equivalente a: |
| |
| [source,java] |
| ---- |
| http://localhost:8080/simple-jms<-TOMEE-VERSION>/message |
| ---- |
| |
| Finalmente, você pode sair ou recarregar o exemplo digitando um dos comandos disponíveis: |
| ``quit``, ``exit``, ``reload``. |
| |
| [source,java] |
| ---- |
| [WARNING] Command '' not understood. Use one of [quit, exit, reload] |
| ---- |