ActiveMq and Springboot - java

I am new to spring boot and am trying to write a consumer using spring boot
Below is my snippet:
application.properties
spring.activemq.broker-url=tcp://localhost:8161
spring.activemq.user=admin
spring.activemq.password=admin
SampleActiveMQApplication.java
#SpringBootApplication
#EnableJms
public class SampleActiveMQApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceAddPayeeApplication.class, args);
}
}
Consumer.java
#Component
public class Consumer {
#JmsListener(destination = "queue/msgQueue")
public void receiveQueue(String text) {
System.out.println("inside consumer");
System.out.println(text);
}
}
I am getting the below error
2018-04-23 07:08:08.277 WARN 9196 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'queue/msgQueue' - trying to recover. Cause: Disposed due to prior exception
2018-04-23 07:08:08.292 ERROR 9196 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Could not refresh JMS Connection for destination 'queue/msgQueue' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: Cannot send, channel has already failed: tcp://127.0.0.1:8161
Please assist:

Are you sure that your broker listens on your specified port 8161? By default, Active-mq admin management consoles listens on port 8161 which is accessible over the browser, and the broker listens on 61616. You may need to confirm that. You can check out for more information here

Related

Spring Boot Change RabbitListener queue name with RefreshScope Annotation

I'm using rabbitmq for messaging and spring cloud config server for config. I'm using rabbitlistener for consuming and keeping queue name in config server. When i change queuename on config server i want RabbitListener to change queuename but it doesn't seem to work. How can I get #rabbitlistener to change queuename when I refresh application through actuator refresh.
#Component
#RefreshScope
public class Listener
{
#RabbitListener(queues="${mq.queue}")
public void listen(#Payload Message message)
{
}
}

Micronaut context configuration for test

I'm trying to write a basic controller test in a micronaut (3.2.7) application. When I run it, it fails to start as it wants to create DB related beans too. micronaut-hibernate-jpa, flyway, etc. are in the pom.xml.
Can I configure the context somehow so it doesn't pick up hikaripool,flyway, and jpa realted beans?
11:46:23.820 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test]
11:46:24.112 [main] WARN i.m.c.h.j.JpaConfiguration$EntityScanConfiguration - Runtime classpath scanning is no longer supported. Use #Introspected to declare the packages you want to index at build time. Example #Introspected(packages="foo.bar", includedAnnotations=Entity.class)
11:46:24.133 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
11:46:25.197 [main] ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"
The code:
class HelloTest {
private static EmbeddedServer server;
private static HttpClient client;
#BeforeAll
public static void setupServer() {
server = ApplicationContext.run(EmbeddedServer.class);
client = server
.getApplicationContext()
.createBean(HttpClient.class, server.getURL());
}
#AfterAll
public static void stopServer() {
if (server != null) {
server.stop();
}
if (client != null) {
client.stop();
}
}
#Test
void testHelloWorldResponse() {
...
}
}
I tried to exclude configurations like this, but with no luck:
server = ApplicationContext.builder("test")
.exclude("io.micronaut.configuration.hibernate.jpa","io.micronaut.configuration.jdbc.hikari")
.run(EmbeddedServer.class);
Note: If I remove everything from application.yml then the test works. It looks like that in tests the default properties are resolved which turns on jpa,metrics, etc. So I guess the test needs to ignore the default settings too somehow.
You can override all of your (default) application.yml with (test-)environment specific property files: https://docs.micronaut.io/latest/guide/index.html#_included_propertysource_loaders
So you can just provide a dedicated application-mycustomtest.yml as part of your test resources, in which you override all default settings.
Then you can specify as part of the test, which environments shall be active:
#MicronautTest(environments={"mycustomtest"})
Asked the micronaut team on gitter and currenlty the only option is not having a default configuration and having multiple configuration files for controller, repo and e2e testing.

How to send message to the rabbitmq queue using spring integration java DSL

I wrote simple sample to read text from console and send it to the rabbitMq server:
#Configuration
#EnableIntegration
#IntegrationComponentScan
public class Config {
#Autowired
private AmqpTemplate amqpTemplate;
#Bean
public IntegrationFlow fromConsoleToRabbitFlow() {
return IntegrationFlows.from(consoleSource(), c -> c.id("consoleInput")
.poller(Pollers.fixedRate(1000))
.autoStartup(true)
).channel("consoleOutputChannel")
.handle(Amqp.outboundAdapter(amqpTemplate).routingKey("my_spring_integration_queue"))
.get();
}
public MessageSource<String> consoleSource() {
return CharacterStreamReadingMessageSource.stdin();
}
}
It looks like almost working solution but I can't find my_spring_integration_queue in rabbitmq admin console:
But I can't find anything related to 'my_spring_integration_queue' on other tab. Where can I find it ?
I expect that application will create queue if it doesn't exist. I was not able to find a method for send into the queur so I used .routingKey method. I also tried .exchangeName method but it lead to the:
32019-08-27 13:26:15.972 ERROR 16372 --- [ 127.0.0.1:5672] o.s.a.r.c.CachingConnectionFactory : Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'my_spring_integration_queue' in vhost '/', class-id=60, method-id=40)
P.S.
the Queue tab looks like this:
You either need to add the queue manually or use a RabbitAdmin #Bean to automatically declare it for you - the admin will find all beans of type Queue and declare them.
If you are using Spring Boot, it will automatically configure an admin bean for you so you just need the Queue #Bean.
See Configuring the Broker.

Spring AMQP transacted channel deadlock

I have a requirement to send a message to a RabbitMQ instance with a JPA entity after persisting/flushing it, which lead me to configure the rabbitTemplate as channelTransacted.
The consumer is external, but, to create an integration test, I have added an embedded broker (Apache QPid) and a listener to be able to check that the messages are sent.
As indicated by the documentation, I seem to have ran into a deadlock:
If we have producers and consumers in the same application, we may end up with a deadlock when producers are blocking the connection (because there are no resources on the Broker any more) and consumers cannot free them (because the connection is blocked). [...]
A separate CachingConnectionFactory is not possible for transactional producers that execute on a consumer thread, since they should reuse the Channel associated with the consumer transactions.
If I set rabbitTemplate.channelTransacted = false, the listener gets invoked fine, otherwise harness.getNextInvocationDataFor just waits until it times out.
What I'm hoping is that there's still a way to do this kind of integration test and that perhaps I configured something wrong.
I've tried with both the simple and the direct listener types, didn't make any difference:
queues:
transactions: 'transactions'
spring:
rabbitmq:
host: rabbitmq
username: guest
password: guest
dynamic: true # automatically create queues and exchanges on the RabbitMQ server
template:
routing-key: ${queues.transactions}
retry.enabled: true
# mandatory: true # interesting only for cases where a reply is expected
# publisher-confirms: true # does not work in transacted mode
publisher-returns: true # required to get notifications in case of send problems
# used for integration tests
listener:
type: direct
direct:
retry:
enabled: true
stateless: false # needed when transacted mode is enabled
max-attempts: 1 # since this is used just for integration tests, we don't want more
I'm using Spring Boot 2.1.3 with the spring-boot-starter-amqp, which pulls in spring-rabbit-2.1.4 and Apache Qpid 7.1.1 as the embedded broker for the test:
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")
#AutoConfigureTestDatabase
#Transactional
#ActiveProfiles("test")
public class SalesTransactionGatewayTest {
private static final String TRANSACTIONS_LISTENER = "transactions";
#TestConfiguration
#RabbitListenerTest(spy = false, capture = true)
public static class Config {
#Bean
public SystemLauncher broker() throws Exception {
SystemLauncher broker = new SystemLauncher();
Map<String, Object> attributes = new HashMap<>();
attributes.put(SystemConfig.TYPE, "Memory");
attributes.put(SystemConfig.INITIAL_CONFIGURATION_LOCATION, "classpath:qpid-config.json");
attributes.put(SystemConfig.STARTUP_LOGGED_TO_SYSTEM_OUT, false);
broker.startup(attributes);
return broker;
}
#Bean
public Listener listener() {
return new Listener();
}
}
public static class Listener {
#RabbitListener(id = TRANSACTIONS_LISTENER, queues = "${queues.transactions}")
public void receive(SalesTransaction transaction) {
Logger.getLogger(Listener.class.getName()).log(Level.INFO, "Received tx: {0}", transaction);
}
}
#Before
public void setUp() {
// this makes the test work, setting it to `true` makes it deadlock
rabbitTemplate.setChannelTransacted(false);
}
#Test
public void shouldBeSentToGateway() throws Exception {
SalesTransaction savedTransaction = service.saveTransaction(salesTransaction);
InvocationData invocationData = this.harness.getNextInvocationDataFor(TRANSACTIONS_LISTENER, 10, TimeUnit.SECONDS);
assertNotNull(invocationData);
assertEquals(salesTransaction, invocationData.getArguments()[0]);
}
}
11:02:56.844 [SimpleAsyncTaskExecutor-1] INFO org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer - SimpleConsumer [queue=transactions, consumerTag=sgen_1 identity=16ef3497] started
Mar 25, 2019 11:02:57 AM AmqpSalesTransactionGateway send
INFO: Sending transaction: 01a92a56-c93b-4d02-af66-66ef007c2817 w/ status COMPLETED
11:02:57.961 [main] INFO org.springframework.amqp.rabbit.connection.CachingConnectionFactory - Attempting to connect to: [localhost:5672]
11:02:57.972 [main] INFO org.springframework.amqp.rabbit.connection.CachingConnectionFactory - Created new connection: rabbitConnectionFactory.publisher#6d543ec2:0/SimpleConnection#79dd79eb [delegate=amqp://guest#127.0.0.1:5672/, localPort= 56501]
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertNotNull(Assert.java:712)
at org.junit.Assert.assertNotNull(Assert.java:722)

Unable to connect to ActiveMQ broker over STOMP through Spring Boot

I am trying to connect to an ActiveMQ broker running on my local machine using Spring Boot as followed from the this link
In the link, an in-memory broker is used but I am more keen on using a broker server, which in my case I am using ActiveMQ
I am specifying the activemq broker to Spring through the following configurations in the file application.properties present in the class path
spring.activemq.broker-url=stomp://localhost:61611
spring.activemq.password=password
spring.activemq.user=admin
Below are the dependencies from my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-stomp -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-stomp</artifactId>
</dependency>
</dependencies>
Below is the log for ActiveMQ after I have started the server on my local machine
INFO | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1#5419f379: startup date [Sun May 07 07:17:36 IST 2017]; root of context hierarchy
INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[F:\Softwares\Browser\apache-activemq-5.14.5-bin\apache-activemq-5.14.5\bin\..\data\kahadb]
INFO | KahaDB is version 6
INFO | Recovering from the journal #1:2260893
INFO | Recovery replayed 3154 operations from the journal in 0.309 seconds.
INFO | PListStore:[F:\Softwares\Browser\apache-activemq-5.14.5-bin\apache-activemq-5.14.5\bin\..\data\localhost\tmp_storage] started
INFO | Apache ActiveMQ 5.14.5 (localhost, ID:FOOTBALL_FIELD-63581-1494121658754-0:1) is starting
INFO | Listening for connections at: tcp://0.0.0.0:61610?maximumConnections=1000&wireFormat.maxFrameSize=104857600
INFO | Connector openwire started
INFO | Listening for connections at: amqp://0.0.0.0:5670?maximumConnections=1000&wireFormat.maxFrameSize=104857600
INFO | Connector amqp started
INFO | Listening for connections at: stomp://0.0.0.0:61611?maximumConnections=1000&wireFormat.maxFrameSize=104857600
INFO | Connector stomp started
INFO | Listening for connections at: mqtt://0.0.0.0:1880?maximumConnections=1000&wireFormat.maxFrameSize=104857600
INFO | Connector mqtt started
WARN | ServletContext#o.e.j.s.ServletContextHandler#338c99c8{/,null,STARTING} has uncovered http methods for path: /
INFO | Listening for connections at ws://127.0.0.1:61612?maximumConnections=1000&wireFormat.maxFrameSize=104857600
INFO | Connector ws started
INFO | Apache ActiveMQ 5.14.5 (localhost, ID:FOOTBALL_FIELD-63581-1494121658754-0:1) started
Application.java
#SpringBootApplication
#EnableJms
public class Application {
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
#Bean // Serialize message content to json using TextMessage
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
public static void main(String[] args) {
// Launch the application
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
// Send a message with a POJO - the template reuse the message converter
System.out.println("Sending an email message.");
jmsTemplate.convertAndSend("mailbox", new Email("info#example.com", "Hello"));
}
}
Requesting DTO Class Email
public class Email {
private String to;
private String body;
//getter setters for fields
//constructors
#Override
public String toString() {
return String.format("Email{to=%s, body=%s}", getTo(), getBody());
}
}
Reponse DTO Class ** **
#Component
public class Receiver {
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(Email email) {
System.out.println("Received <" + email + ">");
}
}
Now when I execute the Spring Boot application, I am getting an error , the stacktrace of which is below
Exception in thread "main" org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=localhost}
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:487)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:570)
at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:658)
at hello.Application.main(Application.java:49)
Caused by: javax.jms.JMSException: Could not create Transport. Reason: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=localhost}
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:333)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:346)
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:304)
at org.apache.activemq.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:244)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:180)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
... 3 more
Caused by: java.lang.IllegalArgumentException: Invalid connect parameters: {wireFormat.host=localhost}
at org.apache.activemq.transport.TransportFactory.doConnect(TransportFactory.java:126)
at org.apache.activemq.transport.TransportFactory.connect(TransportFactory.java:65)
at org.apache.activemq.ActiveMQConnectionFactory.createTransport(ActiveMQConnectionFactory.java:331)
As a result of this, I am unable to connect to the ActiveMQ broker running on my local machine through Spring Boot.
My requirement is to build a JMS Sender and Receiver over STOMP through ActiveMQ broker in Spring Boot Only. But I am unable to connect to the STOMP URL of the instance f ActiveMQ running on my local.
UPDATE : 11.05.2017 :
After a lot of debugging, I managed to find out that at line # 120 of org.apache.activemq.transport.TransportFactory class has this code Transport transport = createTransport(location, wf) is calling the org.apache.activemq.transport.tcp.TcpTransportFactory implementation of org.apache.activemq.transport.TransportFactory instead of org.apache.activemq.transport.stomp.StompTransportFactory or as a matter of fact any of StompTransportFactory implementations available in activemq-stomp.jar being present in classpath. I want to know if any body can tell me how is the appropriate TransportFactory implementation is selected.
I am stuck on this for almost 3 days. Any type of help or suggestion would be appreciated :)
Cheers!
Is there any reason that you want to use STOMP in Java in place of using the normal ActiveMQ Java client and protocols like VM or TCP ?
STOMP is designed for plain text... your exception is due to the fact that you are using the ActiveMQ client to speak STOMP which it cannot do and to do this you need some other libraries for that maybe spring stomp support but it is not exactly what you try to do http://docs.spring.io/spring-integration/reference/html/stomp.html
if you need STOMP you can use this lib and configure the correspondant beans https://github.com/fusesource/stompjms
UPDATE
As i see in this test https://github.com/fusesource/stompjms/blob/master/stompjms-activemq-test/src/test/java/org/fusesource/stomp/activemq/ActiveMQJmsStompTest.java
It is easy to integrate this library to any java or spring client since it implements JMS API.
You have to define a bean for the ConnectionFactory :
add to your application.properties
jms.broker.url=tcp://localhost:61611
And update your configuration :
#Value("${jms.broker.url}")
public String host;
#Bean
public ConnectionFactory connectionFactory() throws Exception {
StompJmsConnectionFactory result = new StompJmsConnectionFactory();
result.setBrokerURI(host);
return result;
}

Categories

Resources