push a dynamic message in Scheduler websocket using spring boot using stomp - spring-boot

I try to make a chatbot using springboot (websocket), i want to know if it's possible to push a dynamic message in Scheduler, and i need some help, i'can't fugure it out.
I want to push the message in the Scheduler Configure how could i do that:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
template.convertAndSend("/topic/user", new UserResponse("Fixed Delay Scheduler"));
}
}
in the sendAdhocMessages method i want to pass a message that will be displayed in an html page. in the Official doc it's impossible to pass a parameter to a method which is annotated by #Scheduled, is there any methd to do that?

The official documentation contains a hint to, how you could pass values to the scheduled method. Maybe you could provide a bean that acts as a message provider. In the scheduler class you autowire the message provider and request the messages.
A short code example:
#Componet
public class MessageProvider {
private String message;
// getter and setter ...
}
In the scheduler you could use the message provider like following:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Autowired
MessageProvider messageProvider;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
String currentMessage = messageProvider.getMessage();
template.convertAndSend("/topic/user", new UserResponse(currentMessage));
}
}

Related

KafkaListener Not triggered in Spring Boot test

I have a spring boot test to check if a kafka consumer listens for a message in specific topic. The kafka listener is triggered when using #SpringBootTest. But I just don't want to load all the classes and I only supplied the listener class like this #SpringBootTest(classes={KafkaConsumerTest.class}).
When only loading the consumer class, the listener has stopped to trigger. Is there something I am missing?
Here is the KafkaTestConsumer class
#Service
public class KafkaTestConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTestConsumer.class);
private CountDownLatch latch = new CountDownLatch(1);
private String payload;
#KafkaListener(topics = {"topic"})
public void receive(ConsumerRecord<?, ?> consumerRecord) {
payload = consumerRecord.toString();
latch.countDown();
}
public CountDownLatch getLatch() {
return latch;
}
public void resetLatch() {
latch = new CountDownLatch(1);
}
public String getPayload() {
return payload;
}
}
It would be great to see what is your KafkaConsumerTest, but perhaps you just override the whole auto-configuration with a plain #Configuration.
See more in docs: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.detecting-configuration
If you want to customize the primary configuration, you can use a nested #TestConfiguration class. Unlike a nested #Configuration class, which would be used instead of your application’s primary configuration, a nested #TestConfiguration class is used in addition to your application’s primary configuration.

Propagate Spring boot security context into a bean annotated with #KafkaListener

I have a bean that is annotated with #KafkaListener and inside this bean, I am planning to get the logged-in user credentials through SecurityContextHolder.
However, SecurityContextHolder.getContext().getAuthentication() is giving me a null object probably because this is running in a different thread.
In this case, is there a way to propagate the SecurityContext from ThreadLocal to another thread? Can it easily be done in my Spring Boot configuration?
Below is the sample code:
#Component
#Slf4j
public class MessageConsumer {
private final MessageService messageService;
#Autowired
public MessageConsumer(final MessageService service) {
messageService = service;
}
#KafkaListener(topics = "myTopic")
public void receive(final List<Message> message) {
messageService.consumerAnStoreMessage(message, SecurityContextHolder.getContext().getAuthentication());
}
}
The SecurityContext's authentication represents, for exemple, a user who called a webservice, a website's page... etc...
When you listen to a kafka message, which user's context should be used ?
I don't think what you are trying to do really makes sens.

Apache Camel Spring Javaconfig Unit Test No consumers available on endpoint

I have the following route configuration:
#Component
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:in").to("direct:out");
}
}
When I try to test it:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyRouteTest.TestConfig.class }, loader = CamelSpringDelegatingTestContextLoader.class)
#MockEndpoints
public class MyRouteTest {
#EndpointInject(uri = "mock:direct:out")
private MockEndpoint mockEndpoint;
#Produce(uri = "direct:in")
private ProducerTemplate producerTemplate;
#Configuration
public static class TestConfig extends SingleRouteCamelConfiguration {
#Bean
#Override
public RouteBuilder route() {
return new MyRoute();
}
}
#Test
public void testRoute() throws Exception {
mockEndpoint.expectedBodiesReceived("Test Message");
producerTemplate.sendBody("Test Message");
mockEndpoint.assertIsSatisfied();
}
}
I get this exception:
org.apache.camel.component.direct.DirectConsumerNotAvailableException:
No consumers available on endpoint: Endpoint[direct://out].
Exchange[Message: Test Message]
It looks like the Mock is not picking up the message from the endpoint.
What am I doing wrong?
The problem is that mock endpoints just intercept the message before delegating to the actual endpoint. Quoted from the docs:
Important: The endpoints are still in action. What happens differently
is that a Mock endpoint is injected and receives the message first and
then delegates the message to the target endpoint. You can view this
as a kind of intercept and delegate or endpoint listener.
The solution to your problem is to tell certain endpoints (the ones that expect a consumer in your case) not to delegate to the actual endpoint. This can easily be done using #MockEndpointsAndSkip instead of #MockEndpoints:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyRouteTest.TestConfig.class }, loader = CamelSpringDelegatingTestContextLoader.class)
#MockEndpointsAndSkip("direct:out") // <-- turns unit test from red to green ;)
public class MyRouteTest {
// ....
}
This issue because, in your route configuration, there is no route with "direct:out" consumer endpoint.
add a line like some thing below,
from("direct:out").("Anything you want to log");
So that direct:out will consume the exchange and In your test, mock will be able check the received text without any issues. Hope this helps !!

Scheduled Tasks in Liferay with Autowired

im trying to create scheduled task in liferay portlet.
Liferay: 6.2
Spring: 3.1.4.RELEASE
With
<scheduler-entry>
<scheduler-description>test-scheduler</scheduler-description>
<scheduler-event-listener-class>
project.ScheduledProcesser
</scheduler-event-listener-class>
<trigger>
<simple>
<simple-trigger-value>
1
</simple-trigger-value>
<time-unit>minute</time-unit>
</simple>
</trigger>
</scheduler-entry>
and the corrensponding class
#Component
public class ScheduledProcesser implements MessageListener {
private static Log log = LogFactoryUtil
.getLog(ScheduledProcesser.class);
#Autowired
#Qualifier("myRequestService")
private RequestService service;
#Override
public void receive(Message message) throws MessageListenerException {
log.info("Starting");
Request req = service.get("AAA746");
if (req!=null)
log.info("REQ -" + req.getId());
log.info("Finished");
}
The method is firing. But the service component is null. Normally is the service in other parts working well.
I have tried to find the solution, but maybe there is some settings missing.
Thanx,
MessageListener is not instantiated by Spring, but by Liferay (see the implementation of QuartzSchedulerEngine.getMessageListener(String, ClassLoader)). And Liferay just instantiates the class. So you can't autowire anything into a MessageListener that is defined in the liferay-portlet.xml.
But you could use PortalBeanLocatorUtil.locate instead, if your service is defined in the portal application context.

How to do integration test with activemq and spring3?

I have a code like this, but I'm not sure how would I test this piece of of code that I extracted from my project. I'm using Spring3 and ActiveMQ. And I'm using spring to do remote HTTPInvoker that's why I have the GateWay. So, when I call method submit in my Gateway, it's going to send a JMS message via JMSDispatcher. How would you inject JmsTemplate to Gateway? As far as I know, if I want to test JMS I have to configure it in application-context.xml in Spring and inject overridden JmsTemplate. So, I could test the message inside the queue? But I can't inject JmsTemplate to Gateway since Mockito will complain about not having that field inside Gateway.
public class Gateway {
#Autowired
private ProcessController processController;
public void submit() {
processControllerFactory.submit();
}
}
public ProcessController {
#Autowired
private JMSDispatcher jmsDispatcher;
public void submit() {
// do something
jmsDispatcher.send(message);
}
}
public JMSDispatcher {
#Autowired
#Qualifier("someJmsTemplate")
private JmsTemplate jmsTemplate;
public void send(MessageCreator message) {
jmsTemplate.send(message);
}
}

Resources